gdalxarray

An xarray backend powered directly by GDAL

import xarray as xr
ds = xr.open_dataset(path_or_uri, engine="gdalxarray")

gdalxarray is a thin bridge between what GDAL can read (classic rasters, multidimensional arrays, and every virtual store GDAL knows about) and xarray’s labelled-array model. It is lazy by default, Dask-chunked on request, and carries CRS and CF time through.

Every code block on this site is run when the site is built, so what you see is what the current release does against the current GDAL. The small inputs are cuts of real public data kept with this repository, each with a script that rebuilds it from its source; the larger examples in the Gallery read public cloud stores, listed with their permanence on the Stores page.

A first look

Three days of NOAA’s daily sea surface temperature analysis (OISST v2.1, a quarter degree, global), written by xarray as Zarr v3, opened by GDAL’s Zarr driver and handed back to xarray:

Data: NOAA 0.25-degree Daily Optimum Interpolation Sea Surface Temperature (OISST), Version 2.1; doi:10.25921/RE9P-PT57; licence: CC0-1.0; days 20250101, 20250102, 20250103. Built by scripts/fixtures/make_oisst.py; details in docs/fixtures/oisst/provenance.json.

src = data("oisst/oisst.zarr")
ds = xr.open_dataset(src, engine="gdalxarray")
ds
<xarray.Dataset> Size: 50MB
Dimensions:  (lat: 720, lon: 1440, time: 3, zlev: 1)
Coordinates:
  * lat      (lat) float32 3kB -89.88 -89.62 -89.38 -89.12 ... 89.38 89.62 89.88
  * lon      (lon) float32 6kB 0.125 0.375 0.625 0.875 ... 359.4 359.6 359.9
  * time     (time) datetime64[ns] 24B 2025-01-01T12:00:00 ... 2025-01-03T12:...
  * zlev     (zlev) float32 4B 0.0
Data variables:
    ice      (time, zlev, lat, lon) float64 25MB ...
    sst      (time, zlev, lat, lon) float64 25MB ...
Attributes:
    license:  CC0-1.0
    source:   doi:10.25921/RE9P-PT57
    title:    NOAA OISST v2.1, three days, as xarray writes them to Zarr v3

Nothing has been read yet beyond the metadata and the coordinate arrays. Selecting and plotting pulls only the chunks needed:

sst = ds["sst"].isel(time=0, zlev=0)
fig, ax = plt.subplots(figsize=(9, 4.4))
sst.plot(ax=ax, cmap="RdYlBu_r", vmin=-2, vmax=32, cbar_kwargs={"label": "degrees C"})
ax.set_title(str(ds.time.values[0])[:10])
plt.show()

Sea surface temperature on the first day, read lazily through GDAL’s Zarr driver. White is land and sea ice.

The same call works for a netCDF on a web server, a COG in a bucket, a multidimensional VRT, a kerchunk-Parquet reference store or an Icechunk repository: only the string changes.

ds.encoding["gdal_driver"], ds["sst"].encoding.get("preferred_chunks")
('Zarr', {'time': 1, 'zlev': 1, 'lat': 360, 'lon': 720})

Where next

Install
GDAL comes first; pip install gdalxarray second.
Guide
The open modes, virtual paths, byte-reference stores, warping, curvilinear grids and georeferencing conventions, each run on small pinned inputs.
Gallery
Worked examples against real cloud stores: OISST, Copernicus Marine ARCO Zarr, BRAN2023, GEBCO, MUR, COP30, Icechunk.
Stores
Every remote store the site uses, how permanent it is, and whether it answered at the last build.

Why this exists (and when to use rioxarray instead)

rioxarray is an accessor and backend built on rasterio. For a single GeoTIFF or a STAC item it is the mature, well-tested choice.

gdalxarray goes straight to osgeo.gdal. That matters when:

  • the data is N-dimensional: GDAL’s multidimensional API is exposed natively, with named dimensions, not only (band, y, x);
  • the path is a composition: /vsicurl/, /vsis3/, /vsizip/, vrt://, ZARR:, NETCDF:, classic and multidim VRT all nest;
  • driver and codec support should track GDAL: Zarr v3, kerchunk Parquet references, Icechunk, GRIB, HDF4/5 multidim.

Status

Active development; the API has settled but may change before 1.0. See the Changelog and the issue tracker.

Rendered with GDAL 3.13.3, xarray 2026.4.1.dev32+g71cfb13ac, numpy 2.5.4, gdalxarray 0.5.1, rasterix 0.2.4.