MapProxy vs TileServer GL for Tile Delivery
Picking the wrong tile server locks a portal into the wrong data model: choose a raster cache when you needed client-side vector styling, or a vector server when your sources are heterogeneous WMS endpoints, and you pay for it in CPU, bandwidth, and re-platforming. This guide compares MapProxy and TileServer GL as tile-delivery engines so platform teams can commit to the right one before the traffic arrives.
This comparison sits within the Infrastructure Orchestration & Configuration Management practice and pairs a decision framework with a concrete hybrid topology. It weighs the two servers on their tile model, source flexibility, reprojection and grid support, styling, caching, client stack, and scaling profile — the axes that actually decide which one survives production.
The core split: pre-rendered rasters vs client-side vectors
Everything downstream follows from one architectural choice — where the map is drawn. MapProxy is a raster-first engine: it fetches map images from upstream OGC services, optionally reprojects and re-tiles them, and stores the finished pixels in a cache. What the browser receives is a completed PNG or JPEG; the server did the drawing. That model is decades-proven, trivially cacheable at every layer, and completely agnostic to how capable the client device is, because the client only ever paints images onto a grid.
TileServer GL inverts that. It serves Mapbox Vector Tiles (MVT) — compact, quantized geometry with feature attributes — and defers rendering to the client. A MapLibre GL browser downloads the vector tiles plus a style JSON and rasterizes them on the GPU in real time. The same tile can be restyled, relabeled, rotated, tilted, or filtered without a single new request to the server, because styling is a client concern decoupled from data delivery. The cost is a heavier, WebGL-dependent client and a data pipeline that must produce vector tiles in the first place.
The practical consequence is that these two servers answer different questions. MapProxy answers “how do I put existing raster and WMS layers in front of many clients, fast, in whatever projection they need?” TileServer GL answers “how do I ship one compact vector dataset that many differently-styled, interactive maps can render themselves?” Confusing the two leads to either re-rendering raster tiles you could have cached once, or shipping raster images where you wanted live restyling.
Source flexibility and the data pipeline
MapProxy’s headline strength is source promiscuity. It will front any WMS, WMTS, TMS, or Mapbox-style raster source, cascade several of them behind one endpoint, and merge or clip layers on the way through. This is exactly why it slots so naturally in front of a GeoServer or a fleet of legacy agency WMS services — you point it at what already exists. It is also why it appears in the portal architecture comparison at GeoNode vs MapProxy Architecture Comparison: it is a caching data plane, not a data producer.
TileServer GL is narrower by design. It serves vector (and raster) tiles out of MBTiles or PMTiles archives — it does not proxy a live WMS. That means an upstream build step: you generate vector tiles with a tool such as tippecanoe or planetiler, package them into an .mbtiles or .pmtiles file, and hand that immutable artifact to the server. The trade is real. TileServer GL loses the “point it at anything” flexibility but gains a reproducible, versionable data artifact that is a single file, cache-friendly at the CDN, and cheap to replicate to every stateless replica.
| Dimension | MapProxy | TileServer GL |
|---|---|---|
| Primary tile model | Pre-rendered raster (PNG/JPEG) | Vector tiles (MVT), rendered client-side |
| Upstream sources | Any WMS / WMTS / TMS, cascaded | MBTiles / PMTiles archive (pre-built) |
| Reprojection | On the fly, arbitrary EPSG grids | None at serve time; bake grid at build |
| Styling model | Baked into cached image | GL style JSON, restyled in the client |
| Data pipeline | Point at existing services | tippecanoe / planetiler build step |
| Native client | OpenLayers, Leaflet (raster) | MapLibre GL (WebGL) |
| CPU cost | Reprojection + rendering on miss | Low server CPU; work moves to client GPU |
| Bandwidth | Larger images, many per view | Compact tiles, restyle without refetch |
| Statefulness | Cache only (disposable) | Read-only archive (immutable) |
Reprojection and tile grids
Reprojection is where the two diverge most sharply, and it is the axis that most often forces the decision. MapProxy is a genuine reprojection engine: it can take a source in one CRS and serve it in another, aligning output to arbitrary tile grids and OGC well-known scale sets on the fly. If your clients demand EPSG:25832, EPSG:3035, and Web Mercator from the same source, MapProxy handles it as a first-class feature, and grid alignment stays compliant with the OGC WMTS specification so heterogeneous clients see consistent tile boundaries.
TileServer GL does no serve-time reprojection. Vector tiles are effectively locked to the Web Mercator (EPSG:3857) grid baked in at build time by the tiling tool. For the overwhelming majority of web-mapping workloads that is exactly what you want and it is why the ecosystem standardized on it — but if your mandate includes national grids or polar projections, that constraint is disqualifying on its own. The rule of thumb: multi-projection or legacy-CRS requirements point at MapProxy; Web-Mercator-only interactive maps point at TileServer GL.
Styling: server-baked pixels vs the GL style spec
With MapProxy, styling lives upstream. The WMS source decides the cartography, MapProxy caches the resulting image, and changing the look means re-rendering and re-seeding the cache. That is a strength when the styling is authoritative and rarely changes — a cadastral basemap looks identical to every client, forever, with zero client compute.
TileServer GL exposes the full MapLibre GL style specification. One vector tile set can drive a light theme, a dark theme, a print theme, and a data-driven choropleth simultaneously, each defined in a JSON style document and switched instantly in the browser. Interactive features — hover states, zoom-dependent labels, feature filtering, 3D extrusion — become client configuration rather than server round-trips. When the product requirement is rich, interactive, restyleable cartography, this is decisive; the MapLibre documentation is the reference for the style spec and GL client.
Where the work happens: server pixels versus client rendering
The split between these two systems is ultimately a decision about which machine does the drawing, and that decision moves cost between budgets you control and budgets you do not. Serving pre-rendered rasters means the server spends CPU once per tile and the client spends almost nothing: any browser, any device, any age of hardware displays the map identically because the pixels arrived finished. Serving vector tiles means the server ships compact geometry and the client spends CPU and memory turning it into pixels on every pan and zoom — which is free for you and not free for a field officer on a five-year-old tablet over a mobile connection.
The variability in the vector payload row is the operational surprise. A raster tile has a predictable size whatever it contains, so capacity planning is arithmetic. A vector tile’s size tracks feature density, so a tile over open countryside is a few kilobytes and a tile over a dense city centre with building footprints and address points can be two orders of magnitude larger — and it is exactly the dense tiles that the most users request. Simplification and per-zoom feature filtering are therefore not polish but a requirement, and they must be verified at the densest part of the extent rather than at a sampled average.
Caching, seeding, and delivery
Both servers cache, but they cache different things. MapProxy’s cache is a warmable store of finished tiles: you pre-seed hot extents so the first user of a busy area never triggers an expensive upstream render, and you back the cache with S3 or Redis so a fleet of stateless replicas shares warmth. Seeding is an operational lever you schedule and tune; the MapProxy documentation covers seed configuration and cache backends in depth.
TileServer GL’s “cache” is upstream of the process: because the MBTiles/PMTiles archive is immutable, the whole delivery path is aggressively cacheable at a CDN with long TTLs and content-hashed URLs. There is no seeding step because there is no rendering-on-miss — the tiles already exist in the archive. In both cases the server should sit behind the same hardened reverse proxy tier described in Reverse Proxy Configuration for WMS/WFS, which terminates TLS, applies rate limits, and caches GetCapabilities-style metadata at the edge.
Scaling and CPU/bandwidth profile
The scaling stories differ in where the work lands. MapProxy spends server CPU on reprojection and rendering at cache-miss time and pushes larger raster payloads over the wire; you scale it by adding stateless workers behind a load balancer and by widening the shared cache so misses are rare. TileServer GL spends very little server CPU — it is essentially reading a file and streaming compact tiles — but it moves rendering cost onto the client GPU and assumes a capable browser. Its replicas are trivially horizontal because the archive is read-only, which makes it an easy fit for the high-availability container pattern in Containerizing TileServer GL for High Availability.
To ground these trade-offs in numbers for your own layers and hardware, do not trust vendor claims — measure. The companion page Benchmarking Tile Latency with k6 walks through a load test that drives randomized tiles at both servers and reports p95/p99 latency for cache-cold and cache-warm runs, which is the only honest way to size either tier.
How each option behaves when the data changes
Publishing cadence separates these two systems more sharply than raw performance does, because the cost of an update is asymmetric. Changing a raster archive means re-rendering every affected tile at every affected zoom, and the affected set is larger than intuition suggests: a single edited parcel boundary invalidates one tile at zoom 18, four at 19, and sixteen at 20, plus the shallower tiles that contain it. Changing a vector archive means re-slicing the affected features, once, at whatever zoom range they are published for — and changing only the appearance means changing a style file and nothing else.
Read the first row as the decision rule for portals whose cartography is still evolving. If the map’s appearance is expected to change more than once a quarter — a new accessibility palette, a print variant, a themed view for a public campaign — the raster path spends its life re-seeding, and each re-seed is a window during which the archive is partly old and partly new. If instead the cartography is settled and the data is the thing that moves, the raster path’s fixed per-tile cost and universal client support are genuine advantages, and the seeding work becomes a predictable scheduled job rather than a recurring project. Portals that need both usually reach the hybrid topology described below for exactly this reason: a settled basemap as rasters, and the thematic layers that change with policy as vectors.
When MapProxy fits
Reach for MapProxy when the sources you must serve are existing WMS/WMTS services and you cannot or will not rebuild them into vector tiles; when clients need multiple projections or non-Mercator grids; when the cartography is authoritative and server-baked rasters are acceptable; and when you want a caching layer that fronts a GeoServer to absorb read traffic without touching the database. Government and agency portals with heterogeneous legacy raster catalogs are the archetype — MapProxy meets the data where it already lives.
When TileServer GL fits
Reach for TileServer GL when the product is an interactive, restyleable web map on Web Mercator; when you can run a tiling build step to produce a versioned MBTiles/PMTiles artifact; when bandwidth and client interactivity matter more than server-side projection flexibility; and when you want dead-simple, immutable, horizontally trivial replicas. Modern public-facing basemaps, data-exploration dashboards, and anything that needs light/dark themes or client-side filtering are the archetype — the vector model pays for its build step many times over.
A hybrid delivery topology
The mature answer is frequently both, split by layer type rather than chosen wholesale. Serve interactive, Web-Mercator vector layers — basemaps, points of interest, boundaries the user filters and restyles — from TileServer GL, and serve authoritative or multi-projection raster layers — orthoimagery, scanned maps, legacy agency WMS — from MapProxy. A single reverse proxy fronts both under one origin so the browser sees a coherent API, and both tiers share the same load balancer, TLS termination, rate limiting, and observability. This mirrors the general split articulated in the portal architecture comparison: a stateless, read-optimized delivery plane, composed here of two specialized servers each doing what it is best at, in front of the same governed data core.
The consumers you did not design for
A public portal’s tile endpoint acquires consumers nobody planned: a desktop GIS project file that a planning officer saved four years ago, an embedded map in a parish council website, a mobile application built by a contractor whose engagement ended, a print pipeline that fetches tiles to compose an A0 wall map. These consumers do not read release notes, do not upgrade, and will not tell you they exist until they break — and they are disproportionately affected by a change in delivery model, because a raster endpoint is consumable by anything that speaks WMS or XYZ while a vector endpoint requires a client capable of styling.
That asymmetry belongs in the decision. Moving a settled public basemap from rasters to vectors is not only a technology change; it is a compatibility break for every consumer that cannot render a style, and the ones that cannot are exactly the long-lived, unattended integrations that make a portal useful to an agency. The practical mitigation is to keep a raster endpoint alive as a rendered view of the same vector source, so modern clients get the small, restylable payloads and everything else keeps working unchanged. That costs a rendering tier you would otherwise have retired, which is a real and ongoing expense — and it is usually cheaper than discovering, from a complaint two districts away, that a statutory map has been blank for a month.
Before any migration, measure the shape of the existing consumers rather than assuming: group a month of access logs by user agent and referrer, and be prepared to find that a meaningful share of traffic comes from clients you have never heard of.
Recommendation
Do not treat this as a single global choice. Classify each layer by projection need, styling need, and whether a vector build step is feasible, then route it to the server that matches. If you can only run one, let the dominant requirement decide: multi-projection or live-WMS fronting means MapProxy; interactive Web-Mercator cartography with a build pipeline means TileServer GL. Whichever you pick, set scaling thresholds from measured latency under representative load rather than defaults, and keep the delivery tier stateless so it scales independently of the metadata and write path.
Related
- Containerizing TileServer GL for High Availability — packaging the vector-tile server as trivially horizontal, immutable replicas.
- Benchmarking Tile Latency with k6 — the load test that turns this comparison into p95/p99 numbers for your own layers.
- GeoNode vs MapProxy Architecture Comparison — where a caching data plane sits relative to the governance control plane.
- Reverse Proxy Configuration for WMS/WFS — the shared edge tier that fronts either tile server.
Up one level: Infrastructure Orchestration & Configuration Management.