Tiny map rendering server for MapLibre Style Spec
npm install chiitiler!GitHub Release
!Unit Tests
!Integration Tests

> Chiitiler is a tiny MapLibre server that renders raster tiles and map cut-outs from any MapLibre Style JSON, with built-in caching backends for source assets and a lightweight debug UI.
Chiitiler accepts remote or local style.json definitions and serves raster tiles or bounding-box images on demand. It was inspired by maptiler/tileserver-gl and developmentseed/titiler but is intentionally minimal, scriptable, and easy to self-host.
- Zero-config startup: point Chiitiler at a style URL or POST a style object to receive tiles.
- Optimized for ephemeral serverless runtimes such as AWS Lambda.
- Multiple cache adapters (memory, file, s3, gcs) to cache shared source assets (MVT tiles, glyphs, sprites) and reduce redundant fetches.
- Built-in /debug and /editor pages to preview styles during development.
- MIERUNE/tiles – see the live example map.
- dayjournal/qgis-amazonlocationservice-plugin – powering QGIS integrations.
- PLATEAU VIEW – serving Cesium.js imagery through the /tiles endpoint.
- Allmaps Latest (Bluesky).
Chiitiler can load tiles, sprites, glyphs, and assets via:
- http:// and https://
- s3:// (AWS S3 or compatible endpoints)
- gs:// (Google Cloud Storage)
- file://
- mbtiles://
- pmtiles://
- cog:// (Cloud Optimized GeoTIFF, CRS must be EPSG:3857)
```
src/
main.ts # CLI entry point and cluster bootstrap
cli.ts # Commander-based CLI definition
server/ # Hono HTTP server & debug UI
render/ # Rasterization and Sharp pipelines
cache/ # Cache adapters (none/memory/file/s3/gcs)
source/ # Helpers for reading external sources
tests/ # Vitest integration & benchmark suites
localdata/ # Sample styles and tiles for demos
cdk/ # AWS CDK deployment project
- Node.js 24.12.0 or newer (.node-version is provided).sharp
- System dependencies to support (see Dockerfile for reference).
`bash`
git clone https://github.com/Kanahiro/chiitiler.git
cd chiitiler
npm install
npx tsx src/main.ts tile-server --port 3000 --debug
When the server starts you can request a tile:
``
http://localhost:3000/tiles/0/0/0.png?url=https://tile.openstreetmap.jp/styles/osm-bright/style.json
`bash`
docker pull ghcr.io/kanahiro/chiitiler:latest
docker run --rm -p 3000:3000 \
-e CHIITILER_CACHE_METHOD=memory \
-e CHIITILER_CACHE_TTL_SEC=600 \
ghcr.io/kanahiro/chiitiler:latest
The container entrypoint wraps node /app/build/main.cjs tile-server, so command-line options can be provided via env vars or by overriding the container CMD explicitly.
#### docker-compose (local S3 + GCS emulation)
The included docker-compose.yml spins up MinIO and fake-gcs-server:
`bash`
docker compose up
Volumes mount localdata/ and .cache/ so test assets and cached source data persist between runs.
| Method | Path Pattern | Description |
| ------ | ------------ | ----------- |
| GET/POST | /tiles/{z}/{x}/{y}.{ext} | Render a raster tile (png, jpeg, jpg, webp). |/clip.{ext}
| GET/POST | | Render a bounding box image (png, jpeg, jpg, webp). |/camera/{zoom}/{lat}/{lon}/{bearing}/{pitch}/{width}x{height}.{ext}
| GET/POST | | Render a static image (png, jpeg, jpg, webp). |/debug
| GET | | Style explorer UI (requires debug mode). |/editor
| GET | | Lightweight style editor (requires debug mode). |
- url – Required when using GET. Points to a MapLibre Style JSON.tileSize
- – Tile size in pixels (default 512).quality
- – JPEG/WebP quality (default 100).margin
- – Tile edge margin (default 0).bbox
- – Bounding box for /clip as minLon,minLat,maxLon,maxLat.size
- – Longest edge of /clip output (default 1024).
POST requests accept the style object directly in the JSON body ({ "style": { ... } }).
Chiitiler exposes a single command: tile-server.
`bash`
npx tsx src/main.ts tile-server --help
| Option | Description | Environment Fallback | Default |
| ------ | ----------- | -------------------- | ------- |
| --cache | Select cache backend. | CHIITILER_CACHE_METHOD | none |--cache-ttl
| | TTL for memory/file caches. | CHIITILER_CACHE_TTL_SEC | 3600 |--memory-cache-max-item-count
| | Max items in memory cache. | CHIITILER_MEMORYCACHE_MAXITEMCOUNT | 1000 |--file-cache-dir
| | Disk cache directory. | CHIITILER_FILECACHE_DIR | ./.cache |--s3-cache-bucket
| | S3 bucket for caching. | CHIITILER_S3CACHE_BUCKET | "" |--s3-region
| | S3 region used for requests. | CHIITILER_S3_REGION | us-east-1 |--s3-endpoint
| | S3-compatible endpoint. | CHIITILER_S3_ENDPOINT | "" |--s3-force-path-style
| | Force path-style requests. | CHIITILER_S3_FORCE_PATH_STYLE (true/false) | false |--gcs-cache-bucket
| | GCS bucket for caching. | CHIITILER_GCS_CACHE_BUCKET | "" |--gcs-project-id
| | GCP project ID. | CHIITILER_GCS_PROJECT_ID | "" |--gcs-key-filename
| | Service account JSON. | CHIITILER_GCS_KEY_FILENAME | "" |--gcs-cache-prefix
| | GCS object prefix. | CHIITILER_GCS_CACHE_PREFIX | "" |--gcs-api-endpoint
| | Custom GCS endpoint. | CHIITILER_GCS_API_ENDPOINT | "" |--port
| | HTTP listen port. | CHIITILER_PORT | 3000 |--debug
| | Enable debug UI routes. | CHIITILER_DEBUG | false |
Set CHIITILER_PROCESSES to control clustering (0 uses all CPUs). When >1, the primary process forks workers that all share the same cache adapter.
In addition to the CLI options above, the server respects:
| Variable | Default | Notes |
| -------- | ------- | ----- |
| CHIITILER_PROCESSES | 1 | Number of worker processes; 0 = availableParallelism(). |AWS_ACCESS_KEY_ID
| / AWS_SECRET_ACCESS_KEY | – | Used by the S3 cache adapter. |AWS_REGION
| | – | Overrides SDK default region if set. |GOOGLE_APPLICATION_CREDENTIALS
| | – | Path to a service account JSON used by the GCS adapter. |
Chiitiler caches the source material required for rendering (vector tiles, glyphs, sprites, spritesheets), not the final raster outputs. These cached assets are reused across requests to avoid refetching upstream sources.
- none – No caching; every request renders from scratch.
- memory – In-memory LRU cache with configurable TTL and max entries.
- file – Stores fetched source assets under CHIITILER_FILECACHE_DIR.fake-gcs-server
- s3 – Uploads cached source assets to S3/MinIO; honors custom endpoint and path-style.
- gcs – Uploads cached source assets to Google Cloud Storage or .
Each adapter exposes the same get/set interface and can be reused when embedding Chiitiler as a library.
Run with --debug or CHIITILER_DEBUG=true to unlock:
- /debug – Inspect styles, test queries, and view response metadata./editor
- – Lightweight MapLibre style editor with live preview.
`bash`
npm run dev # Watch mode via tsx
npm run build # Bundle to build/main.cjs with esbuild
npm run test:unit # Vitest unit suite (src/*/.test.ts)
npm run test:integration # End-to-end scenarios in tests/
npm run test:coverage # Unit coverage with V8 provider
npm run test:benchmark # Performance tests (see BENCHMARK.md)
Benchmark scenarios and recent measurements live in BENCHMARK.md.
Chiitiler is also published as an npm library. Core helpers return Sharp instances or encoded buffers so you can integrate the renderer into other pipelines.
`ts
import {
getRenderedTileBuffer,
getRenderedClipBuffer,
getRenderedCameraBuffer,
getRenderedTileStream,
getRenderedClipStream,
getRenderedCameraStream,
ChiitilerCache,
} from 'chiitiler';
const cache = ChiitilerCache.fileCache({ dir: './.cache', ttl: 3600 });
const tile = await getRenderedTileBuffer({
stylejson: 'https://tile.openstreetmap.jp/styles/osm-bright/style.json',
z: 5,
x: 27,
y: 12,
tileSize: 512,
margin: 0,
ext: 'webp',
quality: 100,
cache,
});
const clip = await getRenderedClipBuffer({
stylejson: 'file://localdata/style.json',
bbox: [123.4, 34.5, 124.5, 35.6],
size: 1024,
ext: 'png',
quality: 95,
cache: ChiitilerCache.noneCache(),
});
const camera = await getRenderedCameraBuffer({
stylejson: 'file://localdata/style.json',
center: [139.69, 35.68],
zoom: 10,
bearing: 180,
pitch: 60,
width: 1024,
height: 1024,
ext: 'png',
quality: 95,
cache,
});
// you can get Sharp streams directly
const tileStream = await getRenderedTileStream({
stylejson: 'https://tile.openstreetmap.jp/styles/osm-bright/style.json',
z: 5,
x: 27,
y: 12,
tileSize: 512,
margin: 0,
ext: 'png',
quality: 90,
cache,
});
const clipStream = await getRenderedClipStream({
stylejson: 'file://localdata/style.json',
bbox: [123.4, 34.5, 124.5, 35.6],
size: 1024,
ext: 'jpeg',
quality: 85,
cache,
});
const cameraStream = await getRenderedCameraStream({
stylejson: 'file://localdata/style.json',
center: [139.69, 35.68],
zoom: 10,
bearing: 180,
pitch: 60,
width: 1024,
height: 1024,
ext: 'png',
quality: 95,
cache,
})
`
The cdk/ directory contains an AWS CDK app for running Chiitiler on Lambda with Web Adapter.
`mermaid
graph LR
subgraph sources
direction LR
A[style.json]
z/x/y.pbf
z/x/y.png/webp/jpg
sprite
glyphs
end
subgraph chiitiler
cache
render
server
end
sources --> cache --> render --> server --/tiles/z/x/y--> png/webp/jpg
cache <--get/set--> memory/file/s3/gcs
``