Tileserver RS uses a TOML configuration file to define tile sources, styles, and server settings.
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
[[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"
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.| Option | Description | Default |
|---|---|---|
host | IP address to bind to | 0.0.0.0 |
port | Port number | 8080 |
cors_origins | Allowed CORS origins | ["*"] |
File-based sources (PMTiles, MBTiles) are configured in [[sources]] arrays. PostgreSQL sources are configured separately in [postgres].
Each file source requires:
| Option | Description | Required |
|---|---|---|
id | Unique identifier | Yes |
type | pmtiles or mbtiles | Yes |
path | Path to tile file (local or URL) | Yes |
name | Display name | No |
attribution | Map attribution | No |
[[sources]]
id = "world"
type = "pmtiles"
path = "/data/world.pmtiles"
# Or from a URL (requires http feature)
# path = "https://example.com/tiles.pmtiles"
[[sources]]
id = "local-data"
type = "mbtiles"
path = "/data/local.mbtiles"
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
| Option | Description | Default |
|---|---|---|
connection_string | PostgreSQL connection URL | Required |
pool_size | Maximum connections | 20 |
ssl_cert | Path to SSL certificate | - |
ssl_key | Path to SSL key | - |
ssl_root_cert | Path to SSL root certificate | - |
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
| Option | Description | Default |
|---|---|---|
id | Unique source identifier | Required |
schema | PostgreSQL schema | public |
table | Table name | Required |
geometry_column | Geometry column name | Auto-detected |
id_column | Column for feature IDs | - |
properties | Columns to include | All non-geometry columns |
minzoom | Minimum zoom level | 0 |
maxzoom | Maximum zoom level | 22 |
bounds | Bounds [west, south, east, north] | Auto-detected |
extent | MVT tile extent | 4096 |
buffer | Tile buffer in pixels | 64 |
max_features | Max features per tile | Unlimited |
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;
| Option | Description | Default |
|---|---|---|
id | Unique source identifier | Required |
schema | PostgreSQL schema | public |
function | Function name | Required |
minzoom | Minimum zoom level | 0 |
maxzoom | Maximum zoom level | 22 |
bounds | Bounds [west, south, east, north] | - |
| Aspect | Table Source | Function Source |
|---|---|---|
| Setup | Minimal config | Requires SQL function |
| Performance | Optimized (uses spatial index) | Depends on function |
| Flexibility | Fixed schema | Custom SQL logic |
| Use case | Standard tables | Complex queries, joins |
[[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
├── sprite@2x.json
└── sprite@2x.png
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/
└── ...
Optionally serve static files from a directory:
files = "/data/files"
Files in this directory will be accessible at /files/{filepath}. This is useful for:
| Variable | Description | Default |
|---|---|---|
RUST_LOG | Log level (error, warn, info, debug, trace) | info |
CONFIG_PATH | Path to config file | config.toml |
HOST | Override server host | - |
PORT | Override server port | - |
tileserver-rs --help
Options:
-c, --config <FILE> Path to configuration file [default: config.toml]
-h, --host <HOST> Override server host
-p, --port <PORT> Override server port
-v, --verbose Enable verbose logging
--help Print help
--version Print version