This page is the canonical reference for everything tileserver-rs reads —
CLI flags, config keys (TOML or YAML), and environment variables — sourced directly
from the Rust structs in crates/tileserver-rs/src/config.rs and
crates/tileserver-rs/src/cli.rs.
Config file formats
tileserver-rs accepts both TOML and YAML config files. The format is detected from the file extension:
| Extension | Parser |
|---|---|
.toml | TOML (default) |
.yaml, .yml | YAML |
| anything else | TOML (fallthrough) |
TOML and YAML produce identical Config structs — every option documented
on this page works in both formats. See data/configs/example.toml
for the canonical exhaustively-commented reference and data/configs/example.yaml
for the YAML syntax mirror.
# Either of these works:
tileserver-rs --config config.toml
tileserver-rs --config config.yaml
tileserver-rs --config config.yml
For task-oriented guides see
Precedence
When the same value is supplied in multiple places, later sources override earlier ones:
- Hard-coded defaults (lowest priority)
- Config file in TOML or YAML (
--config) - Environment variables (
TILESERVER_*) - CLI flags (highest priority)
Config file lookup
If --config is not provided, the server resolves what to load in this
order:
--config <FILE>— explicit config path (fails if the file does not exist)- Positional
PATH— auto-detect sources/styles from that path (see) - Default locations, tried in order:
./config.toml,./config.yaml,./config.yml, then/etc/tileserver-rs/config.{toml,yaml,yml} - CWD auto-detect — scan the current directory for
.pmtiles,.mbtiles,style.json, and font directories
CLI flags
tileserver-rs [OPTIONS] [PATH] [SUBCOMMAND]
| Flag | Env fallback | Default | Description |
|---|---|---|---|
[PATH] (positional) | — | — | File or directory to auto-detect sources/styles from (zero-config mode) |
-c, --config <FILE> | TILESERVER_CONFIG | — | Path to TOML config file |
--cache-dir <PATH> | TILESERVER_CACHE_DIR | <tmp>/tileserver-rs | Scratch / state directory (uploads, on-disk subsystems). Overrides [cache].dir |
--host <HOST> | TILESERVER_HOST | from [server] | Override bind address |
-p, --port <PORT> | TILESERVER_PORT | from [server] | Override bind port |
--public-url <URL> | TILESERVER_PUBLIC_URL | — | Public URL embedded in TileJSON tiles entries |
--ui | TILESERVER_UI | true | Serve the embedded SPA web UI |
--no-ui | — | — | Disable the embedded SPA web UI |
-v, --verbose | — | false | Increase log verbosity |
Subcommands
| Subcommand | Feature gate | Description |
|---|---|---|
| (none) | — | Run the HTTP server (default) |
mcp-stdio | mcp | Run the |
[server]
[server]
host = "0.0.0.0"
port = 8080
cors_origins = ["*"]
admin_bind = "127.0.0.1:0"
public_url = "https://tiles.example.com" # optional
upload_dir = "/var/lib/tileserver/uploads" # optional
upload_max_size_mb = 500
disable_render = false # optional — turn off raster routes
disable_ogc = false # optional — turn off OGC API routes
| Key | Type | Default | Description |
|---|---|---|---|
host | string | "0.0.0.0" | Bind address for the public tile server |
port | u16 | 8080 | Bind port for the public tile server |
cors_origins | string | ["*"] | CORS allow-list — supports literals, glob (*), and regex (/.../); see Pattern syntax below |
admin_bind | string | "127.0.0.1:0" | Separate bind for admin endpoints (/__admin/reload, /__admin/oauth/*). :0 disables. Use 127.0.0.1:8081 to enable. |
public_url | string? | (none) | Public URL embedded in TileJSON. Falls back to the bind address |
upload_dir | path? | system tmp | Directory for drag-and-drop uploads (creates a tmp source per upload) |
upload_max_size_mb | u32 | 500 | Maximum per-file upload size in megabytes |
extra_response_headers | table? | (none) | User-defined response headers applied to every HTTP response — see [server.extra_response_headers] below |
disable_render | bool | false | Unregister raster render routes (raster tiles + static images) at startup. Style metadata (style.json, sprites, WMTS) stays served. Disabled routes return 404. |
disable_ogc | bool | false | Unregister OGC API routes (/ogc/*) at startup. No effect unless built with the ogc feature. Disabled routes return 404. |
CORS origin patterns
The cors_origins list accepts three syntaxes, dispatched per entry:
| Entry syntax | Interpretation |
|---|---|
"*" | Wildcard — allow any origin (default; emits a startup warning) |
"https://example.com" | Exact literal match (unchanged from previous behaviour) |
"*.example.com" | Glob — * matches one or more characters in the Origin URL |
"preview-*.example.com" | Glob — * can appear anywhere in the pattern |
"/^https://.+\\.example\\.com$/" | Regex — enclosed in /.../, matched against the full Origin |
[server]
cors_origins = [
"https://example.com",
"*.cdn.example.com",
"preview-*.example.com",
"/^https://.+\\.team-[a-z0-9]+\\.app\\.example\\.com$/",
]
Notes:
- Entries are tried in order; the first match short-circuits per request.
- A list containing
"*"ALWAYS resolves to wildcard regardless of other entries — that is the existing semantics, preserved. - Pure-literal lists (no
*, no/.../) use the same allocation-freeAllowOrigin::listfast-path as before. Adding a glob or regex switches the layer toAllowOrigin::predicate. - Invalid regex (e.g. unbalanced
[) fails fast at startup with the offending entry quoted in the error. - Glob entries are compiled by anchoring with
^...$and replacing*with.*— so*.x.commatchesfoo.x.comandhttps://foo.x.com, but NOTx.com(no leading subdomain) orfoo.x.com.evil.com(suffix injection blocked).
[server.extra_response_headers]
A user-defined map of HTTP response headers that are applied (in
SetResponseHeaderLayer::overriding mode) to every response served by
tileserver-rs — tile, style, OGC, admin, MCP, everything. Useful for:
| Use case | Example header |
|---|---|
| Edge / CDN cache control | CDN-Cache-Control, Surrogate-Control |
| Browser cache control | Cache-Control (overrides any default) |
| Block search-engine indexing | X-Robots-Tag: noindex, nofollow |
| HSTS for TLS terminators | Strict-Transport-Security |
| Content security | X-Content-Type-Options: nosniff |
| APM correlation | Server-Timing, custom X-* audit headers |
[server.extra_response_headers]
"Cache-Control" = "public, max-age=86400, immutable"
"CDN-Cache-Control" = "max-age=604800"
"X-Robots-Tag" = "noindex, nofollow"
"X-Content-Type-Options" = "nosniff"
"Strict-Transport-Security" = "max-age=31536000; includeSubDomains"
"Server-Timing" = "tileserver;dur=0"
Equivalent YAML:
server:
extra_response_headers:
Cache-Control: public, max-age=86400, immutable
CDN-Cache-Control: max-age=604800
X-Robots-Tag: noindex, nofollow
Rules:
- Header names must conform to RFC 7230 token grammar (alphanumeric +
!#$%&'*+-.^_\|~`). - The transport-managed headers
Content-Length,Transfer-Encoding,Date,Connectionare rejected at startup — the server fails fast. - An empty string value (
"X-Foo" = "") removes any pre-existingX-Fooheader from outgoing responses. - User values are
overriding— they win over anything an upstream middleware emits. - Hot reload (
POST /__admin/reload) picks up changes without a restart.
[[sources]]
Each [[sources]] block configures one tile source. The type field
determines which optional fields are read.
Common fields
| Key | Type | Required | Description |
|---|---|---|---|
id | string | yes | Unique identifier (becomes /data/<id>/* route) |
type | enum | yes | One of: pmtiles, mbtiles, postgres, cog, vrt, geoparquet, duckdb, stac (some feature-gated) |
path | string | yes | File path, HTTP(S) URL, or cloud URL (s3://, gs://, az://) |
name | string? | no | Display name shown in the viewer |
attribution | string? | no | Attribution text included in TileJSON |
description | string? | no | Free-form description |
minzoom | u8? | no | Override the minzoom from source metadata |
maxzoom | u8? | no | Override the maxzoom from source metadata |
serve_as | enum? | no | Transcode on the fly. E.g. serve_as = "mlt" on a PBF source emits MLT. Requires mlt feature |
options | table | no | Key-value map forwarded to cloud backends (S3 credentials, GCS keys, etc.) — see Cloud sources |
Type-specific fields
type = "pmtiles" / type = "mbtiles"
These read all metadata (zoom range, bounds, layers) from the file itself.
No extra config needed beyond id, type, and path.
type = "dir"
Serve a {z}/{x}/{y}.{ext} pyramid straight from disk — no PMTiles/MBTiles
packaging step. The lowest-friction source: point it at tippecanoe
--output-to-directory output, a wget --recursive mirror, or any on-disk
pyramid. Zero startup index cost; every tile fetch is a direct filesystem read.
[[sources]]
id = "tippecanoe-output"
type = "dir"
path = "/data/tiles/openmaptiles/"
# tile_path_template = "{z}/{x}/{y}@2x.png" # optional, default {z}/{x}/{y}.{ext}
# tms = true # optional, default false (XYZ)
minzoom, maxzoom, and bounds are derived lazily by walking the directory
on the first TileJSON request, then cached. Missing tiles behave like every
other source. For tilesets with millions of files, the natural
{z}/{x}/{y} sharding keeps per-directory entry counts manageable.
type = "tar"
Serve a .tar bundle of {z}/{x}/{y}.{ext} tiles — a single portable file,
ideal for airgapped / offline / scp-everywhere deployments. The archive is
decompressed once at startup and an in-memory (z, x, y) index is built; tiles
are then served via random access. Compression is auto-detected by extension:
.tar, .tar.gz / .tgz, .tar.br, .tar.zst.
[[sources]]
id = "regional-tiles"
type = "tar"
path = "/data/tiles.tar.gz" # or .tar / .tar.br / .tar.zst
Vector layer metadata is introspected from the first MVT tile, exactly like the PMTiles source. Tradeoff: the whole archive is held resident in memory (the index alone is ~16 bytes per tile). For planet-scale tilesets, PMTiles remains the production choice — its hierarchical directory avoids keeping every tile in memory.
dir / tar shared options
Both filesystem-style sources accept two extra fields:
| Option | Default | Description |
|---|---|---|
tile_path_template | {z}/{x}/{y}.{ext} | Layout template. Must contain {z}, {x}, {y}; {ext} is optional. Example: {z}/{x}/{y}@2x.png. |
tms | false | true flips the Y axis for TMS (south-up) archives. Default false serves XYZ (north-up), what tippecanoe emits and web clients expect. |
type = "postgres" (feature: postgres)
Combines the common fields with one of two patterns: functions or
tables. Defined inside the top-level [postgres] block,
not directly on the source. See the
type = "cog" / type = "vrt" (feature: raster)
| Key | Type | Default | Description |
|---|---|---|---|
resampling | enum? | bilinear | GDAL resampler. One of: nearest, bilinear, cubic, cubicspline, lanczos, average, mode |
colormap | table? | (none) | See ColorMap below |
type = "geoparquet" (feature: geoparquet)
| Key | Type | Required | Description |
|---|---|---|---|
layer_name | string? | no | Override the layer name in emitted MVT tiles |
geometry_column | string? | no | Geometry column name (auto-detected when GeoParquet metadata is present) |
query | string? | no | DuckDB SQL filter applied before tile materialization |
type = "duckdb" (feature: duckdb)
Same layer_name, geometry_column, query as GeoParquet.
type = "stac" (feature: stac)
| Key | Type | Default | Description |
|---|---|---|---|
collection | string? | (none) | STAC collection ID |
asset_role | string | "visual" | Which asset role to render (e.g. "visual", "thumbnail", "data") |
dynamic | bool | false | Enable on-demand STAC search per tile request (vs. one-time discovery at startup) |
max_items | usize | 100 | Max items considered per tile request when dynamic = true |
stac_bbox | f644? | (none) | Override the bbox passed to STAC search |
pixel_selection | enum | first | Mosaic strategy. See Pixel selection |
Pixel selection (feature: stac or raster)
| Variant | Short-circuit | Description |
|---|---|---|
first (default) | yes | First valid pixel wins. Lowest latency |
highest | no | Per-pixel max across all bands. Highlights bright features |
lowest | no | Per-pixel min. Highlights shadows |
mean | no | Per-pixel arithmetic mean |
median | no | Per-pixel median. Robust to outliers |
stdev | no | Per-pixel std-dev. Change detection |
count | no | Per-pixel valid-input count (debug viz, encodes count in red channel) |
lowestcloudcover | yes | Pick the STAC asset with lowest eo:cloud_cover, then first ordering |
ColorMap (feature: raster)
[[sources]]
id = "ndvi"
type = "cog"
path = "/data/ndvi.tif"
[sources.colormap]
type = "discrete" # or "continuous"
rescale_mode = "static" # or "dynamic" / "none"
nodata_color = "#00000000"
[[sources.colormap.entries]]
value = -1.0
color = "#0033cc"
[[sources.colormap.entries]]
value = 0.0
color = "#888888"
| Key | Type | Default | Description |
|---|---|---|---|
type | enum | discrete | discrete = stepped, continuous = interpolated |
rescale_mode | enum | static | static = use entry values verbatim. dynamic = stretch to per-tile data range. none = no rescale |
entries | table | required | List of {value, color} stops |
nodata_color | string? | (none) | Hex color (incl. alpha) for nodata pixels |
[[styles]]
[[styles]]
id = "osm-bright"
path = "/data/styles/osm-bright/style.json"
name = "OSM Bright"
| Key | Type | Required | Description |
|---|---|---|---|
id | string | yes | Style identifier (becomes /styles/<id>/* route) |
path | string | yes | Path to a MapLibre style JSON file |
name | string? | no | Display name shown in the viewer |
attribution | string? | no | Attribution text |
[render]
Native MapLibre raster renderer pool. See
[render]
pool_size = 4
render_timeout_secs = 30
| Key | Type | Default | Description |
|---|---|---|---|
pool_size | usize | 4 | Concurrent renderer worker threads |
render_timeout_secs | u64 | 30 | Per-request render timeout. Requests exceeding this are dropped |
[cache]
Global in-process tile cache (moka backend).
[cache]
enabled = true
max_size_mb = 512
ttl_seconds = 3600
dir = "/var/lib/tileserver" # optional — scratch / state directory
| Key | Type | Default | Description |
|---|---|---|---|
enabled | bool | false | Enable the global tile cache |
max_size_mb | u64 | 512 | Maximum cache size in megabytes |
ttl_seconds | u64 | 3600 | Time-to-live for cache entries |
dir | path? | <tmp>/tileserver-rs | Scratch / state directory for on-disk subsystems (today: uploads). Storage location only — not a cache eviction policy. |
dir sets where on-disk state (e.g. uploads) lives, not the in-memory tile
cache. Resolution precedence (highest first): --cache-dir flag →
TILESERVER_CACHE_DIR env → [cache].dir → <tmp>/tileserver-rs.
[compression]
Negotiates Accept-Encoding per request and serves tile bodies as brotli or
zstd when the client accepts them. By default tiles are served in whatever
encoding the source stores them in (gzip for most PMTiles); enabling brotli or
zstd negotiation produces 15–40% smaller payloads on typical vector tiles.
[compression]
br_quality = 5 # brotli quality 0-11 (default 5)
zstd_level = 3 # zstd level 1-22 (default 3)
minimal_recompression = false # if true, never re-encode — always passthrough
| Key | Type | Default | Description |
|---|---|---|---|
br_quality | u8 | 5 | Brotli quality (0–11). Higher = smaller payload, slower encode. |
zstd_level | i32 | 3 | Zstandard level (1–22). Higher = smaller payload, slower encode. |
minimal_recompression | bool | false | When true, never decode/re-encode — serve the source encoding as-is. |
How negotiation works per request:
- If the source's stored encoding is already in the client's
Accept-Encodingset, it is served as-is (no decode/re-encode). - Otherwise the tile is decoded once and re-encoded to the highest-preference
acceptable encoding, then cached under
(source, z, x, y, encoding)so the re-encode cost is paid once per tile + encoding pair. - Tiles smaller than 200 bytes skip compression — the framing overhead exceeds the savings.
Every tile response carries Vary: Accept-Encoding so CDNs cache one copy per
encoding rather than serving a wrong-encoding copy to a client that cannot
decode it.
Brotli at quality 10–11 can exceed 100 ms per tile. The default q5 favours
first-paint latency; raise it only if you precompute tiles in batch. Set
minimal_recompression = true to disable negotiation entirely and serve source
bytes verbatim.
[raster] (feature: raster)
[raster]
default_resampling = "bilinear"
tile_size = 256
| Key | Type | Default | Description |
|---|---|---|---|
default_resampling | enum | bilinear | Default resampler. Per-source resampling overrides this |
tile_size | u32 | 256 | Output tile size in pixels (set to 512 for retina-native tiles) |
[telemetry]
OpenTelemetry tracing + Prometheus metrics. See
[telemetry]
enabled = true
endpoint = "http://localhost:4317"
service_name = "tileserver-rs"
sample_rate = 1.0
metrics_enabled = true
metrics_export_interval_secs = 30
prometheus_bind = "127.0.0.1:9100"
prometheus_path = "/metrics"
metrics_label_cardinality = "strict"
| Key | Type | Default | Description |
|---|---|---|---|
enabled | bool | false | Enable OTLP trace export |
endpoint | string | "http://localhost:4317" | OTLP gRPC endpoint |
service_name | string | "tileserver-rs" | service.name resource attribute |
sample_rate | f64 | 1.0 | Sampling rate (0.0–1.0). 1.0 = export every span |
metrics_enabled | bool | true | Enable OTLP metrics export (requires enabled = true) |
metrics_export_interval_secs | u64 | 30 | OTLP metrics push interval |
prometheus_bind | string? | (none) | Bind for standalone Prometheus /metrics listener (independent of OTLP). E.g. "127.0.0.1:9100" |
prometheus_path | string | "/metrics" | HTTP path for the Prometheus exposition endpoint |
metrics_label_cardinality | enum | "strict" | strict (bucketed zoom, no tile coords), standard (alias of strict), verbose (full zoom 0..22) |
[postgres] (feature: postgres)
Top-level PostgreSQL pool + per-source registries. See the
[postgres]
connection_string = "postgres://user:pass@localhost:5432/db"
pool_size = 10
pool_wait_timeout_ms = 5000
pool_pre_warm = true
[postgres.cache]
size_mb = 256
ttl_seconds = 300
[[postgres.functions]]
id = "trip_aggregates"
schema = "public"
function = "mvt_trip_aggregates"
minzoom = 6
maxzoom = 14
[[postgres.tables]]
id = "buildings"
schema = "public"
table = "osm_buildings"
geometry_column = "geom"
minzoom = 12
maxzoom = 18
extent = 4096
buffer = 64
[postgres] root
| Key | Type | Default | Description |
|---|---|---|---|
connection_string | string | req | Postgres connection URI |
pool_size | usize | 10 | Connections in the pool |
pool_wait_timeout_ms | u64 | 5000 | Max ms to wait for a free connection |
pool_create_timeout_ms | u64 | 5000 | Max ms to wait when opening a new connection |
pool_recycle_timeout_ms | u64 | 5000 | Max ms to wait recycling a stale connection |
pool_pre_warm | bool | false | Open all pool connections at startup |
ssl_cert, ssl_key, ssl_root_cert | path? | (none) | mTLS / verify-full SSL material |
[postgres.cache]
| Key | Type | Default | Description |
|---|---|---|---|
size_mb | u64 | 256 | Max cache size for Postgres MVT tiles |
ttl_seconds | u64 | 300 | TTL per entry |
[[postgres.functions]]
| Key | Type | Default | Description |
|---|---|---|---|
id | string | req | Source ID |
schema | string | req | Postgres schema |
function | string | req | Function name (takes z/x/y, returns bytea) |
minzoom | u8 | 0 | Min zoom |
maxzoom | u8 | 22 | Max zoom |
bounds | f644? | (none) | Geographic bounds |
[[postgres.tables]]
| Key | Type | Default | Description |
|---|---|---|---|
id | string | req | Source ID |
schema | string | req | Postgres schema |
table | string | req | Table name |
geometry_column | string? | geom | Geometry column |
id_column | string? | (none) | Optional integer ID column carried into MVT features |
properties | string? | all | Column allow-list for MVT properties |
minzoom | u8 | 0 | Min zoom |
maxzoom | u8 | 22 | Max zoom |
extent | u32 | 4096 | MVT extent (4096 = standard) |
buffer | u32 | 64 | Per-tile geometry buffer in pixels (auto-set to 0 for POINT/MULTIPOINT) |
max_features | u32? | (none) | Hard cap on emitted features per tile |
writable | bool | false | Enable OGC API Features POST/PATCH/DELETE on this table |
[mcp] (feature: mcp)
See the
[mcp]
enabled = true
auth_token = "supersecret" # bearer-token mode
cors_origins = ["https://claude.ai"]
[mcp.oauth]
enabled = false # mutually exclusive with auth_token
issuer_url = "https://tiles.example.com"
signing_key_path = "/etc/tileserver/mcp-jwt-key.pem"
token_ttl_secs = 3600
[mcp] root
| Key | Type | Default | Description |
|---|---|---|---|
enabled | bool | false | Mount the /mcp Streamable HTTP service |
auth_token | string? | (none) | Static bearer token. Mutually exclusive with oauth.enabled = true |
cors_origins | string | ["*"] | CORS allow-list for /mcp (lock down in production) |
[mcp.oauth]
| Key | Type | Default | Description |
|---|---|---|---|
enabled | bool | false | Enable RFC 7591 DCR + JWT RS256 OAuth flow |
issuer_url | string? | (none) | Required when enabled = true. Must match the public URL |
signing_key_path | path? | (none) | Required when enabled = true. RSA PKCS#8 PEM private key |
token_ttl_secs | u64 | 3600 | Access-token TTL (clamped to 86400) |
Top-level fields
| Key | Type | Default | Description |
|---|---|---|---|
fonts | path? | (none) | Directory of PBF glyph files served at /fonts/{stack}/{range}.pbf |
files | path? | (none) | Directory of static files served at /files/{filename} |
Cloud sources
For PMTiles hosted on S3, GCS, or Azure, set the URL on path and pass
credentials via options:
[[sources]]
id = "global"
type = "pmtiles"
path = "s3://tiles-bucket/global.pmtiles"
[sources.options]
aws_region = "us-east-1"
aws_access_key_id = "..."
aws_secret_access_key = "..."
Keys in options are forwarded verbatim to
object_store::parse_url_opts.
See the object_store docs for the full list per backend.
Cargo features
When crates/tileserver-rs/Cargo.toml.
| Feature | Default | Description |
|---|---|---|
postgres | Yes | PostgreSQL / PostGIS tile sources (tables + functions); OGC API Features; CQL2 filter |
raster | Yes | GDAL-based COG / VRT raster sources with colormap + band math |
mlt | Yes | MLT (MapLibre Tiles) ↔ MVT on-the-fly transcoding |
cloud | Yes | Cloud PMTiles (S3 / GCS / Azure / HTTPS) via object_store |
stac | Yes | STAC catalog source (implies raster) |
geoparquet | No | Serve tiles from GeoParquet files on-the-fly (Arrow + Parquet) |
duckdb | No | Embedded DuckDB SQL-driven tile source |
mcp | No | MCP server (stdio + Streamable HTTP) with optional OAuth |
mcp-persistence | No | Disk-backed SQLite store for the MCP OAuth state (implies mcp) |
frontend | No | Embed the Nuxt web UI into the binary (always-on for prebuilt artifacts) |
# Minimal API-only build (no GDAL, no Postgres, no MLT, no cloud):
cargo build --release --no-default-features
# Default features (postgres + raster + mlt + cloud + stac):
cargo build --release
# Everything, including the web UI and MCP server:
cargo build --release --all-features
The frontend feature is intentionally not a default feature so the
backend can be compiled without building the Nuxt frontend first.
Pre-built binaries, Docker images, and Homebrew bottles always ship with
it included.
Environment variables
Server (Rust binary)
| Variable | Type | Description |
|---|---|---|
TILESERVER_CONFIG | path | Equivalent to --config <FILE> |
TILESERVER_CACHE_DIR | path | Equivalent to --cache-dir <PATH> (overrides [cache].dir) |
TILESERVER_HOST | string | Equivalent to --host <HOST> |
TILESERVER_PORT | u16 | Equivalent to --port <PORT> |
TILESERVER_PUBLIC_URL | url | Equivalent to --public-url <URL> |
TILESERVER_UI | bool | Equivalent to --ui / --no-ui (string "true"/"false") |
RUST_LOG | log spec | tracing_subscriber::EnvFilter directives, e.g. tileserver_rs=debug |
Client (Nuxt dev server)
These only affect pnpm dev:client. Production builds embed the SPA in
the Rust binary and serve same-origin, so no proxy is involved.
| Variable | Default | Description |
|---|---|---|
TILESERVER_BACKEND_PORT | 8080 | Port of the public Rust backend the Vite dev proxy forwards to |
TILESERVER_ADMIN_PORT | 8081 | Port of the admin backend ([server].admin_bind) for /__admin/* proxying |
The client env vars are deliberately not prefixed NUXT_. The
NUXT_* prefix is reserved by Nuxt for runtimeConfig auto-mapping;
these are build-time env vars read by nuxt.config.ts directly.
See