Short answer

GeoJSON is an excellent transport format for small interactive layers and API responses, because any browser and mapping library can fetch and render it without a server. It becomes a liability the moment the file is large or geometrically dense: the browser must download, parse, and hold every vertex in memory before drawing a single feature. The fix is almost never "use a different format for everything" — it is to ship a web copy of the data that has been simplified, precision-trimmed, attribute-pruned, and, past a certain size, served as vector tiles instead of one flat file.

Why a raw export hurts

A typical failure looks like this: a developer asks for "the geology layer as GeoJSON," the analyst exports the full working dataset, and the map either takes ten seconds to appear or freezes the tab. The file was built for desktop analysis, so it carries:

  • Full-resolution geometry — vertices spaced for 1:5,000 cartography even though the web map only ever shows the data at city or regional zoom.
  • 15-digit coordinates — far more precision than any pixel can resolve, multiplying file size.
  • Every attribute column — survey notes, internal IDs, intermediate fields the map never references.
  • No spatial chunking — the browser must load the whole country to show one valley.

GeoJSON is plain text, so all of this is uncompressed verbosity sitting in the payload. The browser parses it into JavaScript objects and builds geometry on the main thread, which is what produces the freeze.

Four levers, in order of impact

1. Simplify geometry

Reduce vertex count with a tolerance matched to your maximum zoom. The Douglas-Peucker algorithm (distance-based) and Visvalingam (area-based, often visually nicer) are the standard choices.

  • In QGIS: Processing → native:simplifygeometries, or Vector → Geometry Tools → Simplify.
  • In PostGIS: ST_SimplifyPreserveTopology(geom, tolerance) — the PreserveTopology variant avoids collapsing thin polygons to nothing.
  • For shared borders (adjacent geology units, administrative areas) use topology-aware simplification so neighbouring polygons keep matching edges and don't develop gaps or overlaps. mapshaper -simplify does this well; plain per-feature simplification does not.
mapshaper geology.geojson -simplify 15% keep-shapes -o geology_web.geojson

2. Cut coordinate precision

Six decimal degrees ≈ 0.11 m; five ≈ 1.1 m. Web displays cannot resolve more. Trimming precision is lossless to the eye and often shaves 20-40% off the file.

ogr2ogr -f GeoJSON out.geojson in.gpkg -lco COORDINATE_PRECISION=6 -lco RFC7946=YES

RFC7946=YES also forces longitude,latitude order in WGS84 and correct polygon winding, which is what web renderers expect.

3. Drop unused attributes

Select only the fields the map actually styles or shows in a popup:

ogr2ogr -f GeoJSON out.geojson in.gpkg -select "unit_code,unit_name,age" -lco RFC7946=YES

Smaller properties objects mean a smaller payload and faster popups.

4. Reproject to WGS84

RFC 7946 GeoJSON must be in WGS84 lon/lat. If your analysis layer is in a projected CRS (say EPSG:32633), reproject on export with -t_srs EPSG:4326; the web map library handles the on-screen projection to Web Mercator itself.

When to stop using flat GeoJSON

Simplification has limits. Once a single payload pushes past roughly a few megabytes, or you need the data legible across many zoom levels, switch to vector tiles. Tiles pre-cut the data into a pyramid of small chunks per zoom and tile coordinate, so the browser only ever downloads what is on screen.

Two common paths:

  • MVT (Mapbox Vector Tiles) generated with tippecanoe, which also does zoom-dependent simplification and feature dropping automatically:

    tippecanoe -zg --drop-densest-as-needed -o geology.mbtiles geology.geojson
    
  • PMTiles, a single-file tile archive served from static hosting or object storage with HTTP range requests — no tile server needed, which suits static sites well.

For datasets that change often or need server-side filtering, a PostGIS-backed tile endpoint (e.g. ST_AsMVT) lets you generate tiles on demand:

SELECT ST_AsMVT(t, 'geology') FROM (
  SELECT unit_code, ST_AsMVTGeom(ST_Transform(geom, 3857), ST_TileEnvelope(z, x, y)) AS geom
  FROM geology
) t;

A practical delivery pipeline

  1. Keep the authoritative, full-resolution data in GeoPackage or PostGIS — never overwrite it.
  2. Produce a derived web copy: reproject to WGS84, simplify to your zoom range, trim precision to 6 decimals, select only display attributes.
  3. If the result is small (a few hundred KB up to ~2 MB) ship it as a static .geojson, gzip-compressed by the web server — GeoJSON's repetitive text compresses very well.
  4. If it is larger or multi-zoom, build vector tiles (tippecanoe → PMTiles, or ST_AsMVT).
  5. Document the simplification tolerance and source version so the web copy is reproducible.

Common pitfalls and why they happen

  • Serving uncompressed GeoJSON. Because it is text, gzip/brotli often cuts the transfer by 5-10x; forgetting to enable compression wastes the easiest win.
  • Per-feature simplification on shared borders. Produces slivers and gaps between adjacent units because each polygon's shared edge is simplified independently. Use topology-aware tools.
  • Over-simplifying small features. A tolerance tuned for coastlines can erase small but important polygons; keep-shapes / ST_SimplifyPreserveTopology guard against this.
  • Shipping the analysis CRS. A projected-CRS GeoJSON technically violates RFC 7946 and confuses libraries that assume lon/lat.
  • Loading a national dataset as one file. No amount of simplification makes a country-scale polygon layer pleasant as flat GeoJSON; that is a tiling job.

QA / validation checklist

  • Measure the gzipped payload size, not the raw size — that is what the user downloads.
  • Verify simplified borders still align between adjacent polygons.
  • Confirm output is WGS84, RFC7946-conformant (lon,lat order, no crs member).
  • Check that small but meaningful features survived simplification.
  • Test on a mid-range mobile device, not just a desktop with a fast connection.

Bathyl perspective

We treat the web layer as a separate product derived from the master data, with its own simplification budget and precision. The deliverable is the recipe — source version, tolerance, attribute selection, tile settings — so the web copy can be rebuilt identically when the geology is updated, rather than re-exported by hand and slowly drifting from the source.

Related reading

Sources