Introduction to Xarray Backends#

In this lesson, we will learn about and how to use xarray’s backends

Learning Goals

  • Learn about xarray’s internal and external backends

  • Learn how xarray selects backend engines

  • Learn how to specify backend engines

What are Xarray Backends#

Xarray supports direct serialization and IO to several file formats, through the use of internal and external backends. Xarray’s internal backends cover many common data formats such as “netCDF4”, “h5netcdf”, and “zarr”. These backends provide a set of instructions that tells xarray how read data and store it into a Dataset, DataTree or DataTree model and are stored in the underlying “backend”.

Xarray also supports external backends such as “rioxarray” and “cfgrib” and even creating your own backend.

See also

You can learn more about xarray’s internal and external with our guide to backends.

Reading a dataset with the netCDF4 engine#

We can read in a dataset by selecting the “netcdf4” engine

import xarray as xr

xr.tutorial.open_dataset("air_temperature", engine="netcdf4")
<xarray.Dataset> Size: 31MB
Dimensions:  (time: 2920, lat: 25, lon: 53)
Coordinates:
  * time     (time) datetime64[ns] 23kB 2013-01-01 ... 2014-12-31T18:00:00
  * lat      (lat) float32 100B 75.0 72.5 70.0 67.5 65.0 ... 22.5 20.0 17.5 15.0
  * lon      (lon) float32 212B 200.0 202.5 205.0 207.5 ... 325.0 327.5 330.0
Data variables:
    air      (time, lat, lon) float64 31MB ...
Attributes:
    Conventions:  COARDS
    title:        4x daily NMC reanalysis (1948)
    description:  Data is from NMC initialized reanalysis\n(4x/day).  These a...
    platform:     Model
    references:   http://www.esrl.noaa.gov/psd/data/gridded/data.ncep.reanaly...

Internal Backend Selection#

When opening a file or URL without explicitly specifying the engine parameter, xarray automatically selects an appropriate backend based on the file path or URL. The backends are tried in order: netcdf4 → h5netcdf → scipy → pydap → zarr.

Check for available backends#

We can get a list of our available engines with list_engines

{'netcdf4': <NetCDF4BackendEntrypoint>
   Open netCDF (.nc, .nc4 and .cdf) and most HDF5 files using netCDF4 in Xarray
   Learn more at https://docs.xarray.dev/en/stable/generated/xarray.backends.NetCDF4BackendEntrypoint.html,
 'h5netcdf': <H5netcdfBackendEntrypoint>
   Open netCDF (.nc, .nc4 and .cdf) and most HDF5 files using h5netcdf in Xarray
   Learn more at https://docs.xarray.dev/en/stable/generated/xarray.backends.H5netcdfBackendEntrypoint.html,
 'scipy': <ScipyBackendEntrypoint>
   Open netCDF files (.nc, .cdf and .nc.gz) using scipy in Xarray
   Learn more at https://docs.xarray.dev/en/stable/generated/xarray.backends.ScipyBackendEntrypoint.html,
 'pydap': <PydapBackendEntrypoint>
   Open remote datasets via OPeNDAP using pydap in Xarray
   Learn more at https://docs.xarray.dev/en/stable/generated/xarray.backends.PydapBackendEntrypoint.html,
 'rasterio': <RasterioBackend>,
 'store': <StoreBackendEntrypoint>
   Open AbstractDataStore instances in Xarray
   Learn more at https://docs.xarray.dev/en/stable/generated/xarray.backends.StoreBackendEntrypoint.html,
 'zarr': <ZarrBackendEntrypoint>
   Open zarr files (.zarr) using zarr in Xarray
   Learn more at https://docs.xarray.dev/en/stable/generated/xarray.backends.ZarrBackendEntrypoint.html}

Reading without specifying engine#

When opening a file or URL without explicitly specifying the engine parameter, xarray automatically selects an appropriate backend based on the file path or URL. The backends are tried in order: netcdf4 → h5netcdf → scipy → pydap → zarr.

In the following example this dataset is read with the “netcdf4” engine without explicitly setting the "engine=netcdf4"

xr.tutorial.open_dataset("air_temperature")
<xarray.Dataset> Size: 31MB
Dimensions:  (time: 2920, lat: 25, lon: 53)
Coordinates:
  * time     (time) datetime64[ns] 23kB 2013-01-01 ... 2014-12-31T18:00:00
  * lat      (lat) float32 100B 75.0 72.5 70.0 67.5 65.0 ... 22.5 20.0 17.5 15.0
  * lon      (lon) float32 212B 200.0 202.5 205.0 207.5 ... 325.0 327.5 330.0
Data variables:
    air      (time, lat, lon) float64 31MB ...
Attributes:
    Conventions:  COARDS
    title:        4x daily NMC reanalysis (1948)
    description:  Data is from NMC initialized reanalysis\n(4x/day).  These a...
    platform:     Model
    references:   http://www.esrl.noaa.gov/psd/data/gridded/data.ncep.reanaly...

Setting engine order#

You can customize the order in which netcdf4 backends are resolved using xr.set_options(netcdf_engine_order=)

Let’s update our engine order to have “h5netcdf” and the “netCDF4” and reopening the dataset

xr.set_options(netcdf_engine_order=["h5netcdf", "netcdf4", "scipy"])
<xarray.core.options.set_options at 0x7f515c0c86e0>

Specifying the wrong backend#

Lets trying specifying a bad engine for opening our dataset

Warning

This will fail because we cannot use the “pydap” engine to read this dataset

xr.tutorial.open_dataset("air_temperature", engine="pydap")
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[5], line 1
----> 1 xr.tutorial.open_dataset("air_temperature", engine="pydap")

File ~/work/xarray-tutorial/xarray-tutorial/.pixi/envs/default/lib/python3.14/site-packages/xarray/tutorial.py:170, in open_dataset(name, cache, cache_dir, engine, **kws)
    166 # retrieve the file
    167 filepath = pooch.retrieve(
    168     url=url, known_hash=None, path=cache_dir, downloader=downloader
    169 )
--> 170 ds = _open_dataset(filepath, engine=engine, **kws)
    171 if not cache:
    172     ds = ds.load()

File ~/work/xarray-tutorial/xarray-tutorial/.pixi/envs/default/lib/python3.14/site-packages/xarray/backends/api.py:613, in open_dataset(filename_or_obj, engine, chunks, cache, decode_cf, mask_and_scale, decode_times, decode_timedelta, use_cftime, concat_characters, decode_coords, drop_variables, create_default_indexes, inline_array, chunked_array_type, from_array_kwargs, backend_kwargs, **kwargs)
    601 decoders = _resolve_decoders_kwargs(
    602     decode_cf,
    603     open_backend_dataset_parameters=backend.open_dataset_parameters,
   (...)    609     decode_coords=decode_coords,
    610 )
    612 overwrite_encoded_chunks = kwargs.pop("overwrite_encoded_chunks", None)
--> 613 backend_ds = backend.open_dataset(
    614     filename_or_obj,
    615     drop_variables=drop_variables,
    616     **decoders,
    617     **kwargs,
    618 )
    619 ds = _dataset_from_backend_dataset(
    620     backend_ds,
    621     filename_or_obj,
   (...)    632     **kwargs,
    633 )
    634 return ds

File ~/work/xarray-tutorial/xarray-tutorial/.pixi/envs/default/lib/python3.14/site-packages/xarray/backends/pydap_.py:279, in PydapBackendEntrypoint.open_dataset(self, filename_or_obj, mask_and_scale, decode_times, concat_characters, decode_coords, drop_variables, use_cftime, decode_timedelta, group, application, session, output_grid, timeout, verify, user_charset, checksums)
    257 def open_dataset(
    258     self,
    259     filename_or_obj: (
   (...)    277     checksums=True,
    278 ) -> Dataset:
--> 279     store = PydapDataStore.open(
    280         url=filename_or_obj,
    281         group=group,
    282         application=application,
    283         session=session,
    284         output_grid=output_grid,
    285         timeout=timeout,
    286         verify=verify,
    287         user_charset=user_charset,
    288         checksums=checksums,
    289     )
    290     store_entrypoint = StoreBackendEntrypoint()
    291     with close_on_error(store):

File ~/work/xarray-tutorial/xarray-tutorial/.pixi/envs/default/lib/python3.14/site-packages/xarray/backends/pydap_.py:141, in PydapDataStore.open(cls, url, group, application, session, output_grid, timeout, verify, user_charset, checksums)
    130 kwargs = {
    131     "url": url,
    132     "application": application,
   (...)    137     "user_charset": user_charset,
    138 }
    139 if isinstance(url, str):
    140     # check uit begins with an acceptable scheme
--> 141     dataset = open_url(**kwargs)
    142 elif hasattr(url, "ds"):
    143     # pydap dataset
    144     dataset = url.ds

File ~/work/xarray-tutorial/xarray-tutorial/.pixi/envs/default/lib/python3.14/site-packages/pydap/client.py:179, in open_url(url, application, session, output_grid, flat, timeout, verify, checksums, user_charset, protocol, batch, use_cache, session_kwargs, cache_kwargs, get_kwargs)
    172 if not session:
    173     session = create_session(
    174         use_cache=use_cache,
    175         session_kwargs=session_kwargs,
    176         cache_kwargs=cache_kwargs,
    177     )
--> 179 handler = DAPHandler(
    180     url,
    181     application,
    182     session,
    183     output_grid=output_grid,
    184     flat=flat,
    185     timeout=timeout,
    186     verify=verify,
    187     checksums=checksums,
    188     user_charset=user_charset,
    189     protocol=protocol,
    190     get_kwargs=get_kwargs,
    191 )
    192 dataset = handler.dataset
    193 dataset._session = session

File ~/work/xarray-tutorial/xarray-tutorial/.pixi/envs/default/lib/python3.14/site-packages/pydap/handlers/dap.py:131, in DAPHandler.__init__(self, url, application, session, output_grid, flat, timeout, verify, checksums, user_charset, protocol, get_kwargs)
    129         self.scheme = "https"
    130 else:
--> 131     self.protocol = self.determine_protocol()
    133 self.projection, self.selection = parse_ce(self.query, self.protocol)
    134 arg = (
    135     self.scheme,
    136     self.netloc,
   (...)    140     self.fragment,
    141 )

File ~/work/xarray-tutorial/xarray-tutorial/.pixi/envs/default/lib/python3.14/site-packages/pydap/handlers/dap.py:157, in DAPHandler.determine_protocol(self)
    155         return protocol
    156     else:
--> 157         raise TypeError(
    158             "Invalid URL scheme - acceptable options are"
    159             "`dap2`, `dap4`. `https` and `http`",
    160         )
    161 if self.query[:4] == "dap4":
    162     return "dap4"

TypeError: Invalid URL scheme - acceptable options are`dap2`, `dap4`. `https` and `http`