Every vector source can be previewed instantly — even if you never authored a
style.json for it. When you request GET /styles/{id}/style.json and no
[[styles]] entry matches {id}, but a vector source with that id exists,
tileserver-rs generates a complete MapLibre GL v8 style on the fly.
When it triggers
| Condition | Result |
|---|---|
A [[styles]] entry matches the id | The configured style is returned (auto-gen is never consulted) |
| No style matches, but a vector source (PMTiles / MBTiles / MLT) shares the id | An auto-generated style is returned (200) |
| No style matches and the source is raster (COG, DEM, PNG) | 404 Style not found |
| Nothing matches the id at all | 404 Style not found |
What the generated style looks like
For each entry in the source's TileJSON vector_layers, three paint layers are
emitted so that any geometry renders regardless of what the layer contains:
- a
filllayer filtered to["==", "$type", "Polygon"] - a
linelayer filtered to["==", "$type", "LineString"] - a
circlelayer filtered to["==", "$type", "Point"]
The $type filter collapses Multi* geometries to their singular form, so the
three filters together cover every feature.
Layers are grouped all fills → all lines → all circles across source-layers
so polygons never paint over points. Each source-layer gets a deterministic
color (a stable hue derived from a hash of the layer id), with fill-outline-color
always set and zoom-interpolated line-width / circle-radius.
Empty or missing vector_layers still yields a valid style with a single
background layer — the viewer renders a blank map rather than erroring.
Example
curl -s http://localhost:8080/styles/protomaps/style.json | jq '.version, (.layers | length)'
# 8
# 10 (background + 3 kinds × 3 source-layers)
The generated style points its source at the TileJSON endpoint
(/data/{id}.json). Any ?key= query is forwarded to that URL and to the
glyphs URL. MLT sources emit inline .pbf tiles because maplibre-gl-js
cannot decode MLT directly.
Providing your own style
To fully control the appearance, add a [[styles]] entry — it always takes
precedence over auto-generation:
[[styles]]
id = "protomaps"
path = "/data/styles/protomaps/style.json"
name = "Protomaps"