Open in playproj

playproj

GuidePerspectiveCones and cylindersSight and shadeSpilhausGlobals and interruptedsPeeling the orangeDistortionEllipsoidGeoidOrthorectifications2 cellsH3 hexagonsL3 binsModel gridsIndex spaceMGRS and Sentinel-2AAT gridTiles and overviewsRectilinear chunksIcechunk and ZarrRasterizeAffineRegular in what?Convex hullCatastrophesTexture mappingPenguin datumFor exampleHomageVicGridNuyinaRhumb linesFrameTime and depthCutawayVoxels


    
Your own chunk grid

Paste a zarr.json (or a chunk_grid with a shape), or give the URL of one array in a store.

How it works

A Zarr array is stored in chunks, and its chunk_grid says where the cuts are. A regular grid has one chunk length per axis. A rectilinear grid has a list of lengths per axis, so the cuts along an axis can fall anywhere, but every cut still runs the whole way across the array: the grid is the cross product of one list per axis, the same tuple of tuples dask has always used for its own chunks. Finding the chunk that holds an index is a division on a regular axis and a search of the running sums on a rectilinear one (point at the bands on the right to see both).

In zarr.json the rectilinear grid is {"name": "rectilinear", "configuration": {"kind": "inline", "chunk_shapes": [...]}}, one entry per axis: an integer (a regular axis), a list of lengths, or [length, count] runs, which can be mixed. The panel shows the chunk_grid of what is drawn. Left, the array in 3D with the chunks pulled apart, the ones a read touches in yellow and the part it wants in orange; right, the cuts along the first axis for both grids, or a mosaic's tiles and the grid their edges make.

The last chunk

When the chunk length does not divide the array's length, a regular grid overhangs the end: there are ceil(n / c) chunks and the last one reaches past the array. Zarr v2 says the contents of that overhang are undefined; Zarr v3 says border chunks always have the full chunk size, and recommends writing the fill value there. A reader decodes the whole chunk, fill and all.

This is the general case of the rectilinear grid: a regular grid is exactly a rectilinear grid with an integer for every axis. The rectilinear grid can also say what is left, [[30, 3], 10] for 100 steps in 30s, and then the last chunk is stored at 10, not padded to 30. Its lengths must add up to at least the array's length, so the last chunk may still overhang (and even whole chunks past the end are allowed, which is what a shrunken array keeps). Only the last chunk on an axis can overhang: every chunk before it holds exactly its listed length.

Days in months, days in years

Months have 28, 29, 30 or 31 days and years have 365 or 366, so daily data chunked one month or one year at a time cannot be a regular grid. With a regular 30-day chunk, February 2024 takes two chunks and half the values read are not wanted; with monthly chunks it is one. A leap year is [31, 29, 31, 30, 31, 30, [31, 2], 30, 31, 30, 31], and years of daily data from 2000 are [366, [365, 3], 366, [365, 3], ...]. This was the leading example in ZEP0003.

The same grid is what you get by appending: each day (or batch) added becomes a new chunk of its own length, where a regular grid would have to rewrite its part-filled last chunk. A time series at one pixel reads every chunk along time either way: what matters there is how the chunks are cut across the map.

Files, and the chunks inside them

The strongest reason for rectilinear grids is virtual references: kerchunk, VirtualiZarr and Icechunk describe a pile of netCDF, HDF5 or TIFF files as one Zarr array whose chunks are byte ranges in the original files. The files' own blocks cannot be changed, so the grid has to fit them. With a regular grid, a file whose length is not a multiple of the chunk leaves a short chunk in the middle of the array; kerchunk refuses it ("irregular chunking at its boundary. This is only allowed for the final array") and VirtualiZarr allows it only on the last file. A rectilinear grid can list each file's chunks, short ones included (orange in the bands).

The catch is padding. HDF5 (so netCDF-4) and tiled TIFF store a file's last chunk at the full chunk size, padded, and a rectilinear chunk is stored at its listed length, so a padded 65-day remainder stored as 100 cannot be referenced as a chunk of 65. Proposals to let a chunk's stored size differ from its length were raised in the rectilinear extension's review and the ZEP meetings, but are not in the spec. Sources that do not pad (TIFF strips, netCDF classic records, files whose length is a multiple of their chunk, or one chunk per file) fit cleanly.

Mosaics: uneven, staggered and overlapping tiles

Uneven tiles. Because there is one list of lengths per axis, every chunk in a column has the same width and every chunk in a row the same height. Tiles of different sizes fit as one chunk each only if they line up in rows and columns. A tile can be several chunks (its own internal blocks, as runs of lengths), so long as those blocks are exact.

Staggered tiles. When rows of tiles are offset, like bricks, every edge cuts the whole array, so the grid that holds them is cut at every tile's edge and most tiles become two or more chunks. For virtual references that only works where those cuts fall on the files' own block boundaries; otherwise the bytes have to be rewritten.

Overlap. A chunk grid is a partition: every index is in exactly one chunk, regular or rectilinear. Two scenes that cover the same pixels cannot both be chunks of one array, so overlap (red) has to be settled before Zarr sees it, by a rule such as GDAL VRT's "values will be taken from the last overlapping input", by warping to a new grid, or by cropping each tile so the footprints meet without overlap. Overlapping or haloed chunks have come up in Zarr discussions (they would need an order, such as timestamps), but nothing has been proposed. HDF5 virtual datasets and GDAL VRT, which place sources at any offset, are the nearest things.

Inside one TIFF or netCDF file

Within one file, every array is a regular grid with an overhanging last block. Neither format has variable block sizes within one array: they appear across files, or across a COG's overviews, each a regular grid of its own.

In one fileBlocksLast block
TIFF tilesone TileWidth x TileLength per imagefull size, padded
TIFF stripsone RowsPerStrip, full widthshort, not padded
COG overviewsa tiled image per levelpadded, per level
netCDF classicrecord variables: 1 along the record dimensionnone
netCDF-4, HDF5one chunk shape per variablefull size, padded

The exceptions are rare: TIFF-FX's StripRowCounts gives strips of different heights, and an HDF5 virtual dataset stitches other datasets of any shape. So both formats have the same style of chunks as a regular Zarr grid, and a rectilinear grid helps only when files are put together.

Where it stands, October 2026

ZEP0003 (Martin Durant and Isaac Virshup, 2022) proposed variable chunking for Zarr and is still a draft. The rectilinear chunk grid extension, by Davis Bennett, building on ZEP0003 and prototyped with Lachlan Deakin at the 2025 Zarr summit, was merged into zarr-extensions in March 2026. Support:

LibraryRectilinear
zarr-python3.2.0 on, behind array.rectilinear_chunks
zarrs (Rust)0.23.8 on
Icechunk2.0.0 on
xarrayreading, 2026.09.0 on
VirtualiZarr, Zarr.jlopen pull requests
GDAL, tensorstore, zarrita.js, netCDF-Cregular only

Zarr arrays read from a URL here are drawn from their zarr.json alone; no chunk is read. Core in src/core/chunkgrid.js, checked in test/check-chunkgrid.mjs (including the extension's own example).

Hash keys: case, grid (reg, rect), c (regular chunk, or the chunk inside each file), a and w (the read), where (map, pixel), ex, cam.

  • Durant, M. and Virshup, I. (2022) ZEP0003: Variable chunking, draft.
  • Bennett, D. (2026) Rectilinear chunk grid, zarr-extensions.
  • Zarr v3 core specification, regular chunk grid; Zarr v2 specification.
  • Hamman, J., Jones, M. and Bennett, D. (2026) Variable length chunks in Zarr, Earthmover blog.
  • zarr-python #3802 (Max Jones), zarrs #284 (Lachlan Deakin), Icechunk #1806 (Deepak Cherian), VirtualiZarr #954 (Max Jones, Tom Nicholas), kerchunk #374 (Isaac Virshup).
  • Discussion: ZEP0003 discussion, zarr-specs #138, zarr-extensions #25.
  • Adobe (1992) TIFF Revision 6.0; OGC Cloud Optimized GeoTIFF standard; Unidata, netCDF file format specifications; The HDF Group, HDF5 chunking and virtual datasets.
  • GDAL gdalbuildvrt.
Source and contributing