Skip to content

Create a Dynamic Tiler

rio-tiler aims to be a lightweight plugin for rasterio to read slippy map tiles from a raster sources.

Given that rio-tiler allows for simple, efficient reading of tiles, you can then leverage rio-tiler to create a dynamic tile server to display raster tiles on a web map.

There are couple tile servers built on top of rio-tiler:

Example Application

To build a simple dynamic tiling application, we can use FastAPI. Note that titiler uses FastAPI internally, so you might consider using titiler instead of making your own API.


  • rio-tiler ~= 4.0
  • fastapi
  • uvicorn

Install with

pip install fastapi uvicorn rio-tiler

"""rio-tiler tile server."""

import os

from fastapi import FastAPI, Query
from starlette.requests import Request
from starlette.responses import Response

from rio_tiler.profiles import img_profiles
from import Reader

app = FastAPI(
    description="A lightweight Cloud Optimized GeoTIFF tile server",

        200: {
            "content": {"image/png": {}}, "description": "Return an image.",
    description="Read COG and return a tile",
def tile(
    z: int,
    x: int,
    y: int,
    url: str = Query(..., description="Cloud Optimized GeoTIFF URL."),
    """Handle tile requests."""
    with Reader(url) as cog:
        img = cog.tile(x, y, z)
    content = img.render(img_format="PNG", **img_profiles.get("png"))
    return Response(content, media_type="image/png")

@app.get("/tilejson.json", responses={200: {"description": "Return a tilejson"}})
def tilejson(
    request: Request,
    url: str = Query(..., description="Cloud Optimized GeoTIFF URL."),
    """Return TileJSON document for a COG."""
    tile_url = str(request.url_for("tile", z="{z}", x="{x}", y="{y}"))
    tile_url = f"{tile_url}?url={url}"

    with Reader(url) as cog:
        return {
            "bounds": cog.geographic_bounds,
            "minzoom": cog.minzoom,
            "maxzoom": cog.maxzoom,
            "name": os.path.basename(url),
            "tiles": [tile_url],

Launch Example

Use uvicorn to launch the application. Note that app:app tells uvicorn to call the app function within, so you must be in the same directory as

uvicorn app:app --reload