Dynamic tiling ecosystem comparison
This page compares the two main FastAPI-based ecosystems for serving Zarr-backed datacubes as tiles: TiTiler (Development Seed) and Xpublish with its plugins (the xpublish-community org, Earthmover, and the wider xarray community). For per-ecosystem detail see the TiTiler ecosystem overview and the Xpublish ecosystem overview. For the client-side equivalent (visualization libraries that bypass a tile server entirely), see the client-side rendering comparison.
Which should I use?
- TiTiler — COG/STAC-first, GDAL-native raster, fast cold start, and a mature cloud-deploy story (Docker, Lambda/ECS). Reach for it when your data is regular or projected raster, or when you need NASA CMR or ESA EOPF integrations.
- Xpublish — xarray-native, with first-class support for irregular grids (curvilinear, triangular FVCOM, HEALPix, cubed-sphere) and a pick-your-protocol plugin model (tiles, WMS, OGC EDR, OPeNDAP). Reach for it for operational scientific data on its native grid.
TiTiler is intended for public-facing slippy-map tiles. Xpublish for research access to the same data on native grids.
Summary
| TiTiler » | Xpublish » | |
|---|---|---|
| Maintainer | Development Seed | xpublish-community (Joe Hamman, Alex Kerney); code © UCAR; xpublish-tiles by Earthmover |
| Shape | Layered Python stack: rio-tiler → titiler.core → titiler.xarray → applications (titiler.application, titiler-cmr, titiler-multidim, titiler-eopf) |
Small xpublish core with independent plugins (xpublish-tiles, xpublish-wms, xpublish-edr, opendap-protocol) |
| Dataset identity | Client-supplied per request: ?url=… on generic endpoints (titiler-eopf/titiler-cmr are path/search exceptions) |
Server-published namespace: /datasets/{id}/…, ids resolved server-side |
| Rendering engine | rio-tiler + GDAL/rasterio |
Datashader |
| Primary inputs | COG, STAC; Zarr/NetCDF/Icechunk via titiler.xarray |
Xarray-native: Zarr (primary), NetCDF, Icechunk |
| Grid topologies | Regular and projected lat/lon are first-class; curvilinear limited; unstructured out of scope | Regular, curvilinear, FVCOM triangular, SELFE, 2D non-dimensional, HEALPix, cubed-sphere, polar |
| Reprojection | GDAL warp (full kernel set) | Custom pyproj: separable 4326→3857 fast path, blocked thread-pool transform for general CRS |
| Tile endpoints | XYZ, WMTS, TileJSON, POST /statistics; no vector tiles |
XYZ, WMTS, OGC Tiles 1.0, full WMS, MVT/GeoJSON vector tiles, OGC EDR, OPeNDAP |
| Conventions | CF via rioxarray (basic), STAC native | CF via cf-xarray (full), flag_values/flag_meanings/flag_colors for categorical, no STAC |
| Caching | Redis (dataset-level) | Plugin-configurable; xpublish-tiles keys on _xpublish_id + dim + variable |
| First request | Fast | Slow (Numba JIT; warm-up required) |
| Deployment | Official Docker images, AWS Lambda/ECS CDK examples | No official images; deployment is hands-on |
| License | MIT | Apache 2.0 |
How they differ
The deeper detail lives on the per-ecosystem pages (linked from the table headers and under Related); this section covers only the contrasts that don't belong to either page on its own.
Structure. TiTiler is a vertically layered stack — rio-tiler and titiler.core at the base, titiler.xarray adding Zarr/NetCDF, opinionated applications on top — with a COG-first lineage that shows up as GDAL-native raster handling, STAC integration, and a deep set of cloud-deploy recipes. Xpublish is a small core plus independent, mix-and-match plugins (tiles, WMS, EDR, OPeNDAP), centered on xarray-native scientific data and the irregular grid topologies operational geoscience uses.
Who names the dataset. This is the difference that drives deployment and security. TiTiler takes the data location as a per-request query parameter (?url=…) on generic, stateless endpoints, so any worker serves any request and the service drops onto Lambda/ECS behind a CDN — at the cost of exposing the location in the URL and an open fetch surface that needs allowed-host limits. Xpublish publishes a server-owned namespace (/datasets/{id}/…) resolved server-side, so the dataset is curated by the operator and stays resident in the process — which is what enables its _xpublish_id caching and stateful EDR/OPeNDAP queries, at the cost of stateful replicas that must share the same registry. (titiler-eopf and titiler-cmr are path/search exceptions to TiTiler's query-parameter model.)
Rendering engine. The engines mirror that split. TiTiler renders through GDAL via rio-tiler (full resampling kernels, band-math expressions, fast cold start). Xpublish-tiles renders through Datashader with Numba Just-in-Time (JIT) and a custom pyproj reprojection — a slow first request in exchange for renderers that handle curvilinear, triangular, and other unstructured grids GDAL can't, picking an engine per grid type.
Picking the right tool
- COG and STAC are the design center, or you need a mix of raster formats from one stack: TiTiler.
- Operational scientific data on irregular grids (FVCOM, SELFE, ROMS curvilinear, HEALPix, ICON triangular): Xpublish with
xpublish-tilesand/orxpublish-wms. - OGC EDR queries (position/area/cube extraction, time-series, profiles): Xpublish with
xpublish-edr. - OPeNDAP clients: Xpublish with
opendap-protocol. - Categorical raster styling from CF
flag_values/flag_meanings/flag_colors, vector tiles, or a legend endpoint: Xpublish-tiles. - NASA CMR or ESA EOPF data: TiTiler via
titiler-cmr, ortitiler-eopfrespectively. - Dynamic tiling of xarray-readable stores (Zarr, NetCDF):
titiler-multidim
A common hybrid is TiTiler for public-facing slippy-map tiles (where its Redis cache and Lambda/ECS deploy story shine) and Xpublish-tiles/EDR for research-oriented access to the same datasets on their native grids.
Related
- Client-side rendering comparison: browser-side libraries (deck.gl-raster,
@carbonplan/maps, zarr-layer, zarr-cesium) and viewer apps (Browzarr, GridLook) that read Zarr directly with no tile server. - TiTiler ecosystem overview, Xpublish ecosystem overview: per-ecosystem detail.
- Xpublish-tiles detail page.