# TiTiler: on demand map tiles from COG, STAC and Zarr through FastAPI

> TiTiler is a set of Python modules for building dynamic raster tile services on FastAPI, covering Cloud Optimized GeoTIFF, STAC catalogues, Zarr datasets and virtual mosaics, with OGC WMTS and OGC Tiles endpoints. It suits organisations that publish imagery and cannot afford a pre-rendering pipeline, and it now installs as a set of namespace packages rather than one metapackage.

**developmentseed/titiler** — Build your own Raster dynamic map tile services

- Repository: https://github.com/developmentseed/titiler
- Website: https://developmentseed.org/titiler/
- Stars: 1,194 · Forks: 256
- Language: Python
- License: MIT
- Published: 2026-10-19 · Updated: 2026-10-19 · Language: en
- Canonical page: https://hysenlabs.com/projects/developmentseed-titiler

## Dynamic tiling: why not pre-render the pyramid

TiTiler is pronounced tee-tiler, and the README explains the name by way of the French petit, where ti is the diminutive. It is a set of Python modules focused on creating FastAPI applications for dynamic tiling.

Dynamic tiling is the design decision everything else follows from. The usual way to publish raster maps is to generate a pyramid of tiles ahead of time, store it in a bucket or on disk, and serve static files. That works well when you know which areas people will look at, and it works badly when you have a large archive and no idea which parts matter, because the pre-rendering step costs time and storage proportional to the whole dataset rather than to the requests.

TiTiler renders the tile when it is asked for. The raster stays where it is, and the service reads the part it needs and encodes a tile. The project is the descendant of cogeo-tiler and cogeo-mosaic-tiler, so the lineage is the pre-rendering and the mosaic predecessors from the same organisation.

The cost of the approach is that compute happens per request, so a service that suddenly becomes popular pays for it in CPU rather than in storage. The benefit is that the first request for a region costs nothing extra in preparation, which is what makes an archive of imagery browsable at all.

The licence is MIT, the project is at version 2.4.0, and the last push to the repository was on 2026-10-13.

## The package split, and the warning about the old metapackage

The installation section opens with a warning, and it is the first thing a new user will hit.

Do not install the package named titiler from PyPI. In late 2025 the project dropped support for that metapackage, and you must now install TiTiler from the package names in the table. The repository links the pull request that made the change.

The reason is visible in the package table. Starting with version 0.3.0, the titiler module was split into a set of Python namespace packages under titiler.{package}, and there are five of them.

titiler.core contains the libraries to create a dynamic tiler for COG and STAC. titiler.xarray does the same for Zarr and NetCDF datasets. titiler.extensions holds the extensions for tiler factories, which is where the pluggable behaviour lives. titiler.mosaic covers MosaicJSON and adds a cogeo-mosaic requirement. titiler.application is the demo package, a FastAPI application with full support of COG, Zarr, STAC and MosaicJSON.

That last one is the honest name for what it is. It is a demo, and it is also a complete, working service, which is the arrangement most teams end up keeping because the alternative is assembling the same application themselves.

The install itself is a normal pip call with the package name spelled out.

```bash
python -m pip install titiler.core
```

or, for the ready made application, titiler.application, which the README notes also installs core, extensions, xarray and mosaic.

## Running the service locally

The demo application is a standard ASGI app, so it runs the way any FastAPI application runs. The README installs uvicorn alongside the package and then launches the app by its module path.

```bash
# Install uvicorn to run the FastAPI application locally
python -m pip install uvicorn

# Launch application locally
uvicorn titiler.application.main:app
```

For development from a checkout, the project uses uv rather than pip, with a dependency group called server and a reload flag so the server restarts as you edit.

```bash
git clone https://github.com/developmentseed/titiler.git
cd titiler

uv sync --group server
uv run uvicorn titiler.application.main:app --reload
```

The dependency groups in pyproject.toml explain the rest. The dev group carries pytest with coverage and asyncio support, along with pystac for STAC validation, boto3, owslib, pre-commit, IPython and jupyter. The docs group carries mkdocs with the material theme and mkdocstrings. The server group carries uvicorn with the standard extra, uvicorn-worker and gunicorn, which is the pair you need to run the application under a process manager rather than a single worker.

The package metadata requires Python 3.11 or later, and the classifiers list 3.11 through 3.14.

## Formats and standards on the output side

The output formats are listed in one line and they are the ones a client actually asks for. TiTiler supports JPEG, JP2, PNG, WEBP, GTIFF and NumpyTile output.

The distinction between WEBP and NumpyTile is worth pausing on. A tile service usually returns an image, but NumpyTile returns the raw pixel array encoded in a specific layout, which exists so that a renderer can take the data without decoding an image, which saves work when the tile is going to be drawn and not displayed.

On the protocol side, the project supports the OGC RESTful WMTS and OGC Tiles APIs, and it states partial support of the OGC Maps API. That word partial is doing real work, and it is the kind of claim worth reading carefully before you promise a client an endpoint. The two full implementations are the ones with mature specifications and broad client support, and the Maps API is newer.

Two more features round it out. Automatic OpenAPI documentation comes from FastAPI itself, so the running service describes its own endpoints. And multiple projections are supported through morecantile, which handles the TileMatrixSets defined by the OGC, so a service can serve the same data in Web Mercator and in whatever else your audience needs.

The pragmatic reading is that TiTiler covers the two standards that matter for a production tile service and starts on the third.

## Data sources: COG, STAC, Zarr and virtual mosaics

The four data sources are the reason the project is split into five packages, since each one is a different kind of access.

Cloud Optimized GeoTIFF support is the core case. A COG is a GeoTIFF arranged so that a viewer can read a window of it over HTTP with a range request, which is what makes dynamic tiling of a large raster possible without downloading the file. The SpatioTemporal Asset Catalog support is what lets the tiler read from a catalogue of items rather than a single file, with a STAC API as the catalogue interface.

Multi-dimensional Zarr dataset support comes through Xarray, which is the difference between tiling a picture and tiling a cube of data. A Zarr array can have a time axis and a band axis, and the xarray package is where the library learns to slice along them.

The fifth source is virtual mosaic support through MosaicJSON, which is a description of a set of tiles that belong together without merging them into one image. The mosaic package adds a cogeo-mosaic requirement, so that layer is a separate dependency on purpose.

The repository structure shows the split as a directory per package under src/titiler, and the docker-compose file shows how they are combined, with the compose service carrying environment flags to disable the STAC, mosaic, COG or Zarr endpoints individually.

That last point matters for deployment. A minimal deployment that only serves COG does not have to expose endpoints for the other three.

## Container images, process managers and the GDAL environment

The deployment story is a container image and a set of environment variables, and the environment variables are the part that needs care.

The compose file sets a group of GDAL configuration values: CPL_TMPDIR pointing at /tmp, GDAL_CACHEMAX at 75 percent, GDAL_INGESTED_BYTES_AT_OPEN, GDAL_DISABLE_READDIR_ON_OPEN set to EMPTY_DIR, and several GDAL_HTTP settings including HTTP_VERSION set to 2. It also enables the VSI cache with VSI_CACHE set to TRUE and a cache size of 536870912 bytes.

Those are not incidental. GDAL's virtual file system is what reads object storage over HTTP, and the cache settings determine how much of a remote file is held in memory between requests. A tile service reading a large COG from S3 without those settings spends its time on range requests.

The compose file also shows the two process managers. The titiler service runs uvicorn with a single worker, and a second service, titiler-gunicorn, extends it and runs gunicorn with the uvicorn worker class, which is the arrangement to copy when you want more than one worker.

Telemetry is on by default in that file, with TITILER_API_TELEMETRY_ENABLED set to True and an OTLP exporter endpoint pointing at an otel-collector service that the compose file depends on. If you deploy without a collector, that dependency is the first thing to look at.

The published image is on the GitHub registry, and the README gives the run command with the platform flag, the port mapping and the uvicorn invocation.

## Where the project stops, and what to check before adopting

Three limits and one practical note.

The Maps API support is partial, and that is stated rather than implied. If a client in your pipeline expects the full OGC Maps API, check the endpoints the running service actually exposes before committing.

The Python floor is 3.11, and the project uses uv with a uv.lock for reproducibility, so an environment that cannot run 3.11 is out.

The dynamic approach has the cost already described, and it is worth quantifying with your own data. A dataset that is mostly read once benefits from pre-rendering, a dataset that is browsed at random does not, and only you know which one you have.

The practical note is the metapackage. An existing environment that has titiler installed from before late 2025 is running a package that is no longer supported, and a pip install that resolves the old name will keep it that way. The fix is to replace it with the namespace packages named in the table, which is a change to your requirements file rather than to your code, but it has to be done deliberately.

## Conclusion

Adopt TiTiler if you publish raster imagery and want tiles rendered on request from Cloud Optimized GeoTIFF, STAC items or Zarr arrays, because the FastAPI application, the OGC endpoints and the container image are all in this repository. Do not install the package named titiler from PyPI, since the project dropped that metapackage in late 2025 and you must install titiler.core, titiler.xarray, titiler.extensions, titiler.mosaic or titiler.application instead. Before you deploy, copy the GDAL environment variables from the compose file, because the VSI cache settings are what make reads against remote object storage bearable.

## FAQ

### How do I install TiTiler?

Install the namespace packages you need, for example python -m pip install titiler.core, titiler.xarray, titiler.extensions, titiler.mosaic or titiler.application. The README carries an explicit warning not to install the package named titiler from PyPI, because support for that metapackage was dropped in late 2025.

### How do I run the TiTiler demo application?

Install uvicorn and start the ASGI app with uvicorn titiler.application.main:app. For development from a checkout the README uses uv sync --group server followed by uv run uvicorn titiler.application.main:app --reload.

### Which map standards does TiTiler implement?

TiTiler supports the OGC RESTful WMTS and OGC Tiles APIs, and states partial support of the OGC Maps API. Output formats include JPEG, JP2, PNG, WEBP, GTIFF and NumpyTile.

### Which data sources can a TiTiler service serve?

Cloud Optimized GeoTIFF, STAC catalogues, Zarr and NetCDF datasets through Xarray, and virtual mosaics described by MosaicJSON. Each corresponds to one of the namespace packages, and the compose file can disable the STAC, mosaic, COG or Zarr endpoints individually.

## Sources

- [developmentseed/titiler on GitHub](https://github.com/developmentseed/titiler)
- [License: MIT](https://github.com/developmentseed/titiler/blob/main/LICENSE)
- [Project website](https://developmentseed.org/titiler/)
- [README](https://github.com/developmentseed/titiler/blob/main/README.md)
- [Releases](https://github.com/developmentseed/titiler/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/developmentseed-titiler
