tilefeed muimsd
winget install --id=muimsd.tilefeed -e PostGIS vector tile pipeline with incremental MBTiles updates via LISTEN/NOTIFY
winget install --id=muimsd.tilefeed -e PostGIS vector tile pipeline with incremental MBTiles updates via LISTEN/NOTIFY
A PostGIS vector tile pipeline for MBTiles generation + incremental updates + HTTP serving + storage publish.
PostGIS ──┬── Tippecanoe ──┐
├── GDAL ────────┤── MBTiles ──┬── Built-in HTTP server
└── Native Rust ─┘ ├── Local copy
├── S3 upload
LISTEN/NOTIFY ── Debounce ── MVT encode ─├── Mapbox Studio
├── Custom command
├── Webhooks (HTTP POST)
└── SSE (Server-Sent Events)
Full generation exports PostGIS layers through one of three backends (Tippecanoe, GDAL, or native Rust) to produce MBTiles. Incremental updates listen for PostgreSQL notifications, debounce and deduplicate affected tiles, re-encode them as MVT protobuf, and write them into the existing MBTiles file. The built-in HTTP server serves tiles directly from MBTiles with ETag caching and TileJSON metadata.
| Tool | Approach | How tilefeed differs |
|---|---|---|
| pg_tileserv | Serves tiles on-the-fly from PostGIS, no caching or pre-generation. | tilefeed pre-generates tiles into MBTiles for predictable latency and CDN-friendly serving. |
| Martin | Full-featured tile server with many backends, but more complex to deploy. | tilefeed is a focused pipeline that generates, serves, and incrementally updates MBTiles. |
| t-rex | Similar pre-generation approach but tightly coupled to its own built-in HTTP server. | tilefeed decouples generation from serving — use the built-in server or bring your own. |
| Tippecanoe cron | Periodic full re-runs via cron or CI. Misses real-time updates and wastes work. | tilefeed adds incremental updates via PostgreSQL LISTEN/NOTIFY, regenerating only affected tiles. |
GET /events) for live tile refresh in frontendsinspect, validate, diff for MBTiles diagnosticsgeneration_backend = "tippecanoe" (default)generation_backend = "gdal"generation_backend = "native"brew tap muimsd/tilefeed
brew install tilefeed
scoop bucket add tilefeed https://github.com/muimsd/tilefeed
scoop install tilefeed
curl -LO https://github.com/muimsd/tilefeed/releases/latest/download/tilefeed_amd64.deb
sudo dpkg -i tilefeed_amd64.deb
curl -LO https://github.com/muimsd/tilefeed/releases/latest/download/tilefeed-x86_64.rpm
sudo rpm -i tilefeed-x86_64.rpm
cargo install tilefeed
docker build -t tilefeed .
docker run -v ./config.toml:/data/config.toml tilefeed serve
Requires Rust 1.70+ and protoc (protobuf compiler).
# Install protoc
# Linux: sudo apt-get install -y protobuf-compiler
# macOS: brew install protobuf
# Windows: choco install protoc
git clone https://github.com/muimsd/tilefeed.git
cd tilefeed
cargo build --release
# Binary: target/release/tilefeed
Download from GitHub Releases:
| Platform | Binary |
|---|---|
| Linux x86_64 | tilefeed-x86_64-unknown-linux-gnu |
| Linux ARM64 | tilefeed-aarch64-unknown-linux-gnu |
| macOS Apple Silicon | tilefeed-aarch64-apple-darwin |
| macOS Intel | tilefeed-x86_64-apple-darwin |
| Windows x86_64 | tilefeed-x86_64-pc-windows-msvc |
tilefeed generate # full tile generation from PostGIS
tilefeed watch # watch LISTEN/NOTIFY for incremental updates
tilefeed run # generate then watch
tilefeed serve # generate, start HTTP server, and watch
tilefeed inspect # inspect MBTiles metadata and statistics
tilefeed validate # validate config against the database
tilefeed diff <a> <b> # compare two MBTiles files
tilefeed -c other.toml serve # use alternate config file
If running from source: cargo run --release -- serve
createdb geodata
psql -d geodata -c "CREATE EXTENSION IF NOT EXISTS postgis"
psql -d geodata < sql/setup_notify.sql
Attach the trigger to each source table:
CREATE TRIGGER tile_update_trigger
AFTER INSERT OR UPDATE OR DELETE ON your_table
FOR EACH ROW
EXECUTE FUNCTION notify_tile_update('your_layer_name');
The trigger layer name must match a [[sources.layers]].name in config.
[database]
host = "localhost"
port = 5432
user = "postgres"
password = "postgres"
dbname = "geodata"
[serve]
host = "0.0.0.0"
port = 3000
# [webhook]
# urls = ["https://example.com/hooks/tilefeed"]
# secret = "my-signing-secret"
# cooldown_secs = 300
[[sources]]
name = "basemap"
mbtiles_path = "./basemap.mbtiles"
min_zoom = 0
max_zoom = 14
# generation_backend = "native" # no external tools needed
[[sources.layers]]
name = "buildings"
table = "buildings"
geometry_column = "geom"
id_column = "id"
srid = 4326
properties = ["name", "type", "height"]
simplify_tolerance = 0.00001
generate_label_points = true
[[sources.layers.property_rules]]
below_zoom = 8
exclude = ["height"]
See full configuration reference for all options.
# Full rebuild + serve + watch
tilefeed serve
# Or step by step:
tilefeed generate # build MBTiles
tilefeed watch # incremental updates only
| Doc | Description |
|---|---|
| Configuration Reference | All config fields, sections, and generation backends |
| Tippecanoe Settings | Fine-tuning Tippecanoe tile generation |
| Tile Serving | Built-in HTTP server, SSE, webhooks, and external alternatives |
| Derived Layers | Auto-generated label points and boundary lines |
| OGR_FDW Integration | Using external data sources via PostgreSQL FDW |
pg_notify('tile_update', ...)publish_on_update = truemax_zoom for overzoom awarenessMIT