Benchmarks Tile servers

Candidates

Martin vs Tegola vs BBOX vs pg_tileserv vs TiPg vs ldproxy

Tick the candidates you care about and the charts, winners and table redraw for just them: same run, same rig, same samples. Winners come from the numbers alone; the story is in the post.

Single-tile latency

Test 1 Buildings z14

Mean latency over one connection. Dense polygon tile: every building footprint in a 1.5 km Prenzlauer Berg tile (about 2,000 polygons). (LOWER ms = FASTER)

Buildings z14 (ms)
Martin13.6 ms
Tegola15.6 ms
BBOX15.2 ms
pg_tileserv13.7 ms
TiPg13.8 ms
ldproxy120.8 ms
ldproxy (PGIS_TILES)18.9 ms
Buildings z14 in ms
Martin13.6 ms
Tegola15.6 ms
BBOX15.2 ms
pg_tileserv13.7 ms
TiPg13.8 ms
ldproxy120.8 ms
ldproxy (PGIS_TILES)18.9 ms

Test 2 Roads z14

Mean latency over one connection. Line tile: every highway=* way in the same Prenzlauer Berg tile (about 2,500 lines). (LOWER ms = FASTER)

Roads z14 (ms)
Martin7.2 ms
Tegola16.5 ms
BBOX9.6 ms
pg_tileserv12.9 ms
TiPg9.2 ms
ldproxy83.6 ms
ldproxy (PGIS_TILES)15.1 ms
Roads z14 in ms
Martin7.2 ms
Tegola16.5 ms
BBOX9.6 ms
pg_tileserv12.9 ms
TiPg9.2 ms
ldproxy83.6 ms
ldproxy (PGIS_TILES)15.1 ms

Test 3 Points z14

Mean latency over one connection. Point tile: amenity, shop and tourism nodes in the same Prenzlauer Berg tile (about 2,800 points). (LOWER ms = FASTER)

Points z14 (ms)
Martin7.7 ms
Tegola17.4 ms
BBOX10.2 ms
pg_tileserv13.9 ms
TiPg8.8 ms
ldproxy89.4 ms
ldproxy (PGIS_TILES)16.2 ms
Points z14 in ms
Martin7.7 ms
Tegola17.4 ms
BBOX10.2 ms
pg_tileserv13.9 ms
TiPg8.8 ms
ldproxy89.4 ms
ldproxy (PGIS_TILES)16.2 ms

Test 4 Boundaries z9

Mean latency over one connection. Low-zoom polygon tile: the 55 administrative boundary polygons covering most of Berlin, city outline included. (LOWER ms = FASTER)

Boundaries z9 (ms)
Martin8.9 ms
Tegola10.8 ms
BBOX10.3 ms
pg_tileserv9.2 ms
TiPg10.4 ms
ldproxy25.4 ms
ldproxy (PGIS_TILES)9.3 ms
Boundaries z9 in ms
Martin8.9 ms
Tegola10.8 ms
BBOX10.3 ms
pg_tileserv9.2 ms
TiPg10.4 ms
ldproxy25.4 ms
ldproxy (PGIS_TILES)9.3 ms

Test 5 Buildings z14, gzip

Mean latency over one connection when the client accepts gzip, as browsers do: the buildings z14 tile including whatever compression the server applies. (LOWER ms = FASTER)

Buildings z14, gzip (ms)
Martin15.4 ms
Tegola14.9 ms
BBOX16.9 ms
pg_tileserv17.2 ms
TiPg17.3 ms
ldproxy119.4 ms
ldproxy (PGIS_TILES)19.2 ms
Buildings z14, gzip in ms
Martin15.4 ms
Tegola14.9 ms
BBOX16.9 ms
pg_tileserv17.2 ms
TiPg17.3 ms
ldproxy119.4 ms
ldproxy (PGIS_TILES)19.2 ms

Winner Martin (13.6 ms)

Throughput under concurrency

Test 1 Throughput, 10 connections

Successful buildings z14 tiles per second with 10 closed-loop clients. (HIGHER req/s = BETTER)

Throughput, 10 connections (req/s)
Martin485.2 req/s
Tegola264.7 req/s
BBOX494.3 req/s
pg_tileserv220.7 req/s
TiPg332.3 req/s
ldproxy33.0 req/s
ldproxy (PGIS_TILES)248.6 req/s
Throughput, 10 connections in req/s
Martin485.2 req/s
Tegola264.7 req/s
BBOX494.3 req/s
pg_tileserv220.7 req/s
TiPg332.3 req/s
ldproxy33.0 req/s
ldproxy (PGIS_TILES)248.6 req/s

Test 2 Throughput, 100 connections

Successful buildings z14 tiles per second with 100 closed-loop clients. (HIGHER req/s = BETTER)

Throughput, 100 connections (req/s)
Martin467.4 req/s
Tegola254.6 req/s
BBOX394.6 req/s
pg_tileserv169.3 req/s
TiPg456.2 req/s
ldproxy24.6 req/s
ldproxy (PGIS_TILES)226.0 req/s
Throughput, 100 connections in req/s
Martin467.4 req/s
Tegola254.6 req/s
BBOX394.6 req/s
pg_tileserv169.3 req/s
TiPg456.2 req/s
ldproxy24.6 req/s
ldproxy (PGIS_TILES)226.0 req/s

Test 3 p99 latency, 10 connections

Median across passes of each pass's p99 response time at 10 connections. A server that completed no request in a pass is charged the whole 12 s pass. (LOWER ms = FASTER)

p99 latency, 10 connections (ms)
Martin44.2 ms
Tegola70.1 ms
BBOX30.8 ms
pg_tileserv83.7 ms
TiPg47.4 ms
ldproxy1.067 s
ldproxy (PGIS_TILES)79.3 ms
p99 latency, 10 connections in ms
Martin44.2 ms
Tegola70.1 ms
BBOX30.8 ms
pg_tileserv83.7 ms
TiPg47.4 ms
ldproxy1.067 s
ldproxy (PGIS_TILES)79.3 ms

Test 4 p99 latency, 100 connections

Median across passes of each pass's p99 response time at 100 connections. A server that completed no request in a pass is charged the whole 12 s pass. (LOWER ms = FASTER)

p99 latency, 100 connections (ms)
Martin233.6 ms
Tegola1.138 s
BBOX289.3 ms
pg_tileserv1.145 s
TiPg486.2 ms
ldproxy4.963 s
ldproxy (PGIS_TILES)1.140 s
p99 latency, 100 connections in ms
Martin233.6 ms
Tegola1.138 s
BBOX289.3 ms
pg_tileserv1.145 s
TiPg486.2 ms
ldproxy4.963 s
ldproxy (PGIS_TILES)1.140 s

Test 5 Failed requests, 100 connections

Non-2xx responses plus connection errors and 60 s timeouts as a share of all requests at 100 connections. (LOWER % = FASTER)

Failed requests, 100 connections (%)
Martin0 %
Tegola0 %
BBOX0 %
pg_tileserv0.1 %
TiPg0 %
ldproxy0 %
ldproxy (PGIS_TILES)0 %
Failed requests, 100 connections in %
Martin0 %
Tegola0 %
BBOX0 %
pg_tileserv0.1 %
TiPg0 %
ldproxy0 %
ldproxy (PGIS_TILES)0 %

Winner Martin (467.4 req/s)

Viewport burst

Test 1 Viewport, mean

Mean wall time until all four z15 building tiles have arrived, requested in parallel. (LOWER ms = FASTER)

Viewport, mean (ms)
Martin5.5 ms
Tegola7.5 ms
BBOX6.6 ms
pg_tileserv5.3 ms
TiPg10.2 ms
ldproxy51.7 ms
ldproxy (PGIS_TILES)10.5 ms
Viewport, mean in ms
Martin5.5 ms
Tegola7.5 ms
BBOX6.6 ms
pg_tileserv5.3 ms
TiPg10.2 ms
ldproxy51.7 ms
ldproxy (PGIS_TILES)10.5 ms

Test 2 Viewport, slowest

The slowest of the measured viewport loads. (LOWER ms = FASTER)

Viewport, slowest (ms)
Martin8.1 ms
Tegola12.2 ms
BBOX9.7 ms
pg_tileserv7.5 ms
TiPg13.6 ms
ldproxy84.8 ms
ldproxy (PGIS_TILES)20.7 ms
Viewport, slowest in ms
Martin8.1 ms
Tegola12.2 ms
BBOX9.7 ms
pg_tileserv7.5 ms
TiPg13.6 ms
ldproxy84.8 ms
ldproxy (PGIS_TILES)20.7 ms

Winner pg_tileserv (5.3 ms)

Cold start and footprint

Test 1 Time to first tile

Mean time from container process start until the building tile is served, including schema discovery, over five starts. (LOWER ms = FASTER)

Time to first tile (ms)
Martin133.0 ms
Tegola142.0 ms
BBOX147.0 ms
pg_tileserv149.0 ms
TiPg508.0 ms
ldproxy3.709 s
ldproxy (PGIS_TILES)3.686 s
Time to first tile in ms
Martin133.0 ms
Tegola142.0 ms
BBOX147.0 ms
pg_tileserv149.0 ms
TiPg508.0 ms
ldproxy3.709 s
ldproxy (PGIS_TILES)3.686 s

Test 2 Idle memory

Container RSS five seconds after the first tile, before any load. (LOWER MB = FASTER)

Idle memory (MB)
Martin9.5 MB
Tegola8.1 MB
BBOX10.9 MB
pg_tileserv4.4 MB
TiPg213.6 MB
ldproxy479.4 MB
ldproxy (PGIS_TILES)447.5 MB
Idle memory in MB
Martin9.5 MB
Tegola8.1 MB
BBOX10.9 MB
pg_tileserv4.4 MB
TiPg213.6 MB
ldproxy479.4 MB
ldproxy (PGIS_TILES)447.5 MB

Test 3 Memory after load

Container RSS right after the concurrency passes. (LOWER MB = FASTER)

Memory after load (MB)
Martin39.8 MB
Tegola46.5 MB
BBOX42.2 MB
pg_tileserv41 MB
TiPg240.5 MB
ldproxy3,225.6 MB
ldproxy (PGIS_TILES)695.7 MB
Memory after load in MB
Martin39.8 MB
Tegola46.5 MB
BBOX42.2 MB
pg_tileserv41 MB
TiPg240.5 MB
ldproxy3,225.6 MB
ldproxy (PGIS_TILES)695.7 MB

Winner Martin (133.0 ms)

Test conditions: rig, corpus, protocol
Rig
Machine
MacBook Pro
Chip
Apple M2 Max
Cores
12 CPU cores (8 performance, 4 efficiency)
Memory
96 GB
OS
macOS 26.6.2 (arm64)
Runtime
Docker 29.4.0 (OrbStack); PostGIS 18 / 3.6.1 in its own container (6 CPUs, 12 GB); one tile server container at a time (4 CPUs, 4 GB); oha 1.16.0 on the host
Protocol
Warmups
3 unmeasured passes
Measured
20 passes per tool
Process
One server container at a time against a shared PostGIS container; 8 database connections per server; 4 workers where the concept exists; 5 cold starts, 20 single-tile passes of 5 requests per tile, 20 four-tile viewport bursts, 8 passes of 12 s at 10 and at 100 connections
Cache
No server-side tile cache anywhere; PostgreSQL buffer cache warm after warmups; tiles requested without compression
Output
oha 1.16.0 JSON (latency percentiles, request counts, status codes); Bun fetch for cold start, parity and viewport bursts; docker stats for RSS

Scorecard

Mean of each section's samples for the candidates you picked. The best value in each column is marked in red.
CandidateSingle-tile latency (ms, lower is better)Throughput under concurrency (req/s, higher is better)Viewport burst (ms, lower is better)Cold start and footprint (ms, lower is better)
Martin13.6 ms467.4 req/s5.5 ms133.0 ms
Tegola15.6 ms254.6 req/s7.5 ms142.2 ms
BBOX15.2 ms394.6 req/s6.6 ms146.8 ms
pg_tileserv13.7 ms169.3 req/s5.3 ms148.8 ms
TiPg13.8 ms456.2 req/s10.2 ms508.0 ms
ldproxy120.8 ms24.6 req/s51.7 ms3.709 s
ldproxy (PGIS_TILES)18.9 ms226.0 req/s10.5 ms3.686 s

Martin is a project of the MapLibre organization. Tegola is a project of the Go Spatial organization. BBOX is developed by Sourcepole. pg_tileserv is developed by Crunchy Data. TiPg is developed by Development Seed. ldproxy is developed by interactive instruments GmbH. Map data: OpenStreetMap contributors, ODbL, via the Geofabrik Berlin extract of 2026-01-01.