Isoline
All posts

Engineering

Serving 40 million parcels as vector tiles without melting PostGIS

How we moved a national cadastre from on-the-fly WMS rendering to pre-generated and dynamic vector tiles, and cut p95 map latency by 92%.

When our client came to us, their parcel viewer took six to ten seconds to render a single viewport at city scale. The stack was classic: GeoServer rendering PNGs from a PostGIS table with 40 million polygons, fronted by a tile cache that was invalidated far too often.

The fix was not a single trick but a layered strategy: pre-generate what rarely changes, render dynamically what does, and make sure the database never does the same work twice.

Split static and dynamic layers

Parcel geometry changes a few thousand times a day. Attributes like ownership status change far more often. We split them: geometry is baked into PMTiles nightly with tippecanoe, while attributes are joined client-side through feature-state from a lightweight JSON endpoint.

This alone removed more than 80% of the load from the database during peak hours.

Use ST_AsMVT for the long tail

For the handful of layers that must be live, we serve tiles directly from PostGIS using ST_AsMVT with carefully tuned simplification per zoom level, spatial indexes on generated columns, and a short-lived CDN cache keyed by a data version.

Results

p95 latency dropped from 6.4s to 480ms, database CPU fell by 70%, and the frontend team gained full control over styling without a round trip to the server. The same approach now powers three other national datasets.