Documentation

Tileserver RS uses a TOML configuration file to define tile sources, styles, and server settings.

Configuration File

Create a config.toml file. Note that root-level options (fonts, files) must come before any [section] headers due to TOML parsing rules:

# Root-level options (must come before [sections])
fonts = "/data/fonts"
files = "/data/files"

[server]
host = "0.0.0.0"
port = 8080
cors_origins = ["*"]

[telemetry]
enabled = false
# endpoint = "http://localhost:4317"
# metrics_enabled = true
# metrics_export_interval_secs = 60

[render]
pool_size = 4
render_timeout_secs = 30

[[sources]]
id = "openmaptiles"
type = "pmtiles"
path = "/data/tiles.pmtiles"
name = "OpenMapTiles"
attribution = "© OpenMapTiles © OpenStreetMap contributors"

[[sources]]
id = "terrain"
type = "mbtiles"
path = "/data/terrain.mbtiles"
name = "Terrain Data"

[[styles]]
id = "osm-bright"
path = "/data/styles/osm-bright/style.json"
Warning

Root-level keys like fonts and files must appear before any section headers ([server], [telemetry], etc.) in the TOML file. Otherwise they will be incorrectly parsed as part of the preceding section.

Server Configuration

OptionDescriptionDefault
hostIP address to bind to0.0.0.0
portPort number8080
cors_originsAllowed CORS origins["*"]
admin_bindAdmin server bind address for hot-reload127.0.0.1:0 (disabled)
upload_dirDirectory for uploaded files-
upload_max_size_mbMaximum upload file size in MB500

Admin Server

The admin server exposes POST /__admin/reload on a separate port for hot-reloading configuration without restarting the server.

[server]
admin_bind = "127.0.0.1:9099"

When admin_bind is set to anything other than 127.0.0.1:0, the admin server starts on that address. You can also trigger a reload by sending SIGHUP to the server process.

See the Hot Reload Guide for details.

File Uploads

Enable file uploads for the drag-and-drop visualization feature:

[server]
upload_dir = "/data/uploads"
upload_max_size_mb = 500

When upload_dir is set, the server exposes upload endpoints (POST /api/upload, GET /api/upload, DELETE /api/upload/{id}) for streaming geospatial files (MBTiles, SQLite, COG) to disk. Uploaded files are registered as temporary tile sources — they persist until deleted or the server restarts.

See the File Drop Guide and Upload API reference for details.

Source Configuration

File-based sources (PMTiles, MBTiles, GeoParquet) are configured in [[sources]] arrays. PostgreSQL sources are configured separately in [postgres].

Each file source requires:

OptionDescriptionRequired
idUnique identifierYes
typepmtiles, mbtiles, geoparquet, or duckdbYes
pathPath to tile file (local or URL)Yes
nameDisplay nameNo
attributionMap attributionNo

PMTiles Sources

[[sources]]
id = "world"
type = "pmtiles"
path = "/data/world.pmtiles"
# Or from a URL (requires http feature)
# path = "https://example.com/tiles.pmtiles"

MBTiles Sources

[[sources]]
id = "local-data"
type = "mbtiles"
path = "/data/local.mbtiles"

GeoParquet Sources

Info

GeoParquet support requires the geoparquet feature flag when building from source.

Serve vector tiles on-the-fly from GeoParquet files — no preprocessing or tile generation step required.

[[sources]]
id = "buildings"
type = "geoparquet"
path = "/data/overture-buildings.parquet"
name = "Overture Buildings"
layer_name = "buildings"
geometry_column = "geometry"
minzoom = 0
maxzoom = 14
OptionDescriptionDefault
layer_nameMVT layer nameSource id
geometry_columnName of the geometry columnAuto-detected
minzoomMinimum zoom level0
maxzoomMaximum zoom level14

GeoParquet 1.1 files with bbox covering columns enable fast spatial filtering via row group pruning.

DuckDB Sources

DuckDB support requires the duckdb feature flag when building from source.

Generate vector tiles on-the-fly from SQL queries against embedded DuckDB databases or GeoParquet files.

id = "places" type = "duckdb" path = "/data/overture.duckdb" query = """ SELECT name, geometry FROM places WHERE bbox.xmin <= {bbox_xmax} AND bbox.xmax >= {bbox_xmin} AND bbox.ymin <= {bbox_ymax} AND bbox.ymax >= {bbox_ymin} """ layer_name = "places"

SQL templates support {z}, {x}, {y}, and {bbox} placeholders that are substituted per tile request. Set path to an empty string for in-memory DuckDB.

PostgreSQL Configuration

Info

PostgreSQL support requires the postgres feature flag when building from source.

Configure PostgreSQL connection and sources in the [postgres] section:

[postgres]
connection_string = "postgresql://user:pass@localhost:5432/tiles"
pool_size = 20

# Table sources (recommended - auto-generates optimized SQL)
[[postgres.tables]]
id = "points"
table = "my_points"
geometry_column = "geom"
minzoom = 0
maxzoom = 14

# Function sources (for custom SQL logic)
[[postgres.functions]]
id = "custom_tiles"
function = "get_tiles"
minzoom = 0
maxzoom = 14

Connection Options

OptionDescriptionDefault
connection_stringPostgreSQL connection URLRequired
pool_sizeMaximum connections20
ssl_certPath to SSL certificate-
ssl_keyPath to SSL key-
ssl_root_certPath to SSL root certificate-

Table Sources

Table sources auto-discover geometry columns and generate optimized tile queries with spatial index filtering.

[[postgres.tables]]
id = "buildings"
schema = "public"
table = "buildings"
geometry_column = "geom"      # Optional, auto-detected
id_column = "id"              # Optional, for feature IDs
properties = ["name", "type"] # Optional, defaults to all columns
minzoom = 0
maxzoom = 14
bounds = [-180, -85, 180, 85] # Optional, auto-detected
extent = 4096                 # MVT extent (default: 4096)
buffer = 64                   # Tile buffer in pixels (default: 64)
max_features = 10000          # Optional feature limit per tile
OptionDescriptionDefault
idUnique source identifierRequired
schemaPostgreSQL schemapublic
tableTable nameRequired
geometry_columnGeometry column nameAuto-detected
id_columnColumn for feature IDs-
propertiesColumns to includeAll non-geometry columns
minzoomMinimum zoom level0
maxzoomMaximum zoom level22
boundsBounds [west, south, east, north]Auto-detected
extentMVT tile extent4096
bufferTile buffer in pixels64
max_featuresMax features per tileUnlimited
Warning

Ensure your geometry column has a spatial index (GIST) for optimal performance. The server will warn if no index is found.

Function Sources

Function sources call PostgreSQL functions that return MVT tiles directly.

[[postgres.functions]]
id = "dynamic_tiles"
schema = "public"
function = "get_tiles"
minzoom = 0
maxzoom = 14
bounds = [-180, -85, 180, 85]

The function must have one of these signatures:

-- Simple (z, x, y)
CREATE FUNCTION get_tiles(z integer, x integer, y integer)
    RETURNS bytea AS $$ ... $$ LANGUAGE plpgsql;

-- With query parameters (z, x, y, query)
CREATE FUNCTION get_tiles(z integer, x integer, y integer, query json)
    RETURNS bytea AS $$ ... $$ LANGUAGE plpgsql;
OptionDescriptionDefault
idUnique source identifierRequired
schemaPostgreSQL schemapublic
functionFunction nameRequired
minzoomMinimum zoom level0
maxzoomMaximum zoom level22
boundsBounds [west, south, east, north]-

Table vs Function Sources

AspectTable SourceFunction Source
SetupMinimal configRequires SQL function
PerformanceOptimized (uses spatial index)Depends on function
FlexibilityFixed schemaCustom SQL logic
Use caseStandard tablesComplex queries, joins

Style Configuration

[[styles]]
id = "bright"
path = "/data/styles/bright/style.json"
name = "Bright Style"  # Optional display name

Styles should include sprites alongside the style.json:

styles/
└── bright/
    ├── style.json
    ├── sprite.json
    ├── sprite.png
    ├── [email protected]
    └── [email protected]

Font Configuration

Fonts are required for rendering text labels. Configure the fonts directory:

fonts = "/data/fonts"

The fonts directory should contain subdirectories for each font family with PBF glyph files:

fonts/
├── Noto Sans Regular/
│   ├── 0-255.pbf
│   ├── 256-511.pbf
│   └── ...
├── Noto Sans Medium/
│   ├── 0-255.pbf
│   └── ...
└── Open Sans Bold/
    └── ...
Info

Font glyph PBF files can be generated using tools like node-fontnik or downloaded from OpenMapTiles fonts.

Static Files Configuration

Optionally serve static files from a directory:

files = "/data/files"

Files in this directory will be accessible at /files/{filepath}. This is useful for:

  • GeoJSON overlays
  • Custom marker icons
  • Other static assets

Telemetry Configuration

tileserver-rs supports OpenTelemetry for exporting traces and metrics via OTLP gRPC.

[telemetry]
enabled = true
endpoint = "http://localhost:4317"
service_name = "tileserver-rs"
sample_rate = 1.0
metrics_enabled = true
metrics_export_interval_secs = 60
OptionDescriptionDefault
enabledEnable OpenTelemetry (traces + metrics)false
endpointOTLP gRPC collector endpointhttp://localhost:4317
service_nameService name for traces and metricstileserver-rs
sample_rateTrace sampling rate (0.0 to 1.0)1.0
metrics_enabledEnable metrics export (requires enabled = true)true
metrics_export_interval_secsHow often metrics are pushed to the collector60

When enabled, the following metrics are exported:

MetricTypeUnitDescription
http.server.request.countCounterrequestsTotal HTTP requests
http.server.request.durationHistogramsecondsRequest duration
http.server.response.body.sizeHistogrambytesResponse body size

Each metric includes attributes: http.request.method, http.response.status_code, url.path.

Info

When telemetry is disabled (the default), metrics recording has zero overhead — all instruments are no-ops.

See the Telemetry Guide for setup examples with Grafana, Jaeger, and other backends.

Render Pool Configuration

Configure the native MapLibre renderer pool for server-side raster tile generation:

[render]
pool_size = 4
render_timeout_secs = 30
OptionDescriptionDefault
pool_sizeNumber of concurrent renderer worker threads4
render_timeout_secsRender timeout in seconds — requests exceeding this fail30

Each worker thread maintains persistent MapLibre Native instances with their own EGL contexts. Increase pool_size for higher concurrent raster tile throughput.

Info

The [render] section is optional. When omitted, the renderer pool starts with default values. If the server was built without MapLibre Native (stub mode), the pool initializes but returns placeholder images.

Environment Variables

VariableDescriptionDefault
RUST_LOGLog level (error, warn, info, debug, trace)info
CONFIG_PATHPath to config fileconfig.toml
HOSTOverride server host-
PORTOverride server port-

CLI Options

tileserver-rs --help

Usage: tileserver-rs [PATH] [OPTIONS]

Arguments:
  [PATH]  Path to a tile file or directory to auto-detect sources/styles from

Options:
  -c, --config <FILE>       Path to configuration file [env: TILESERVER_CONFIG]
      --host <HOST>         Host to bind to [env: TILESERVER_HOST]
  -p, --port <PORT>         Port to bind to [env: TILESERVER_PORT]
      --public-url <URL>    Public URL for tile URLs in TileJSON [env: TILESERVER_PUBLIC_URL]
      --ui                  Enable the web UI (default: true) [env: TILESERVER_UI]
      --no-ui               Disable the web UI
  -v, --verbose             Enable verbose logging
  -h, --help                Print help
  -V, --version             Print version

Config Resolution Priority

The server resolves configuration in this order:

  1. --config <FILE> — explicit config path (fails if file doesn't exist)
  2. Positional PATH — auto-detect sources/styles from that path
  3. Default locations: ./config.toml, /etc/tileserver-rs/config.toml
  4. CWD auto-detect — scan the current directory
Info

Zero-config auto-detect discovers .pmtiles, .mbtiles, style.json, fonts directories, and GeoJSON files. See the Auto-Detect Guide for details.

Cargo Features

When building from source, you can enable optional features:

FeatureDescriptionDefault
postgresPostgreSQL tile sources (tables + functions)Yes
rasterGDAL-based raster/COG tile supportYes
mltMLT transcoding (MLT to MVT and MVT to MLT)Yes
geoparquetServe tiles from GeoParquet files on-the-flyNo
frontendEmbed the Nuxt web UI into the binaryNo
FeatureDescriptionDefault
----------------------------------------------------------------
postgresPostgreSQL tile sources (tables + functions)Yes
rasterGDAL-based raster/COG tile supportYes
mltMLT transcoding (MLT to MVT and MVT to MLT)Yes
duckdbSQL-driven tile generation via embedded DuckDBNo
frontendEmbed the Nuxt web UI into the binaryNo
# API-only (no web UI, no GDAL, no PostgreSQL):
cargo build --release --no-default-features

# Default features (postgres + raster + mlt, no web UI):
cargo build --release

# Everything including the web UI:
cargo build --release --all-features
Info

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 CI release builds always include it.