Home -> Examples -> cos2023

Land cover · vector

Every square metre of Portugal, classified.

Not a sample or a selection: the official map of how all of mainland Portugal is used, from the national mapping agency. 842,413 shapes in 93 classes, with no gaps between them. TerraServe serves it two ways at the same time, from one process holding 75 MB of memory.

cos2023 Portugal land cover in the TerraServe X-ray viewer

The approach

One coverage, two protocols, 75 MB.

Complete, not sampled

A coverage, not a scattering

Most big map datasets are things dotted about: buildings, roads, points. This one tiles the entire country: every square metre belongs to exactly one of 93 classes, and neighbouring shapes share their borders exactly. That's much harder to serve, because no matter where you look there's always something to draw. There's no empty space to skip.

Two views, one process

A picture for QGIS, shapes for the browser

The same layer answers as WMS, where the server draws a picture and sends it, which is what desktop GIS expects, and as vector tiles, where the raw shapes go to the browser and it does the drawing, so you can restyle and click individual parcels. Same data, same process, two completely different jobs.

Read only where you look

A 1.4 GB file in 75 MB of memory

The file is never loaded. TerraServe uses its spatial index to fetch only the shapes inside the area you asked for, so memory tracks your screen, not the dataset. It starts in 8 seconds and settles around 75 MB, small enough that we run two copies behind a load balancer for redundancy.

How it's served

The exact command.

This is the real command behind the live demo: two identical copies of it, load-balanced. Every flag, explained below.

terraserve serve # land cover of Portugal, WMS + vector tiles
  --vector /data/cos2023v1.fgb
  --vec-style /data/cos2023.sld  --src-crs EPSG:3763  --name cos2023
  --mvt-style /data/cos2023.mvt-style.json  --mvt-min-feature-px 8.0
  --pmtiles /data-cache/cos2023.pmtiles  --mvt-cache 0
  --wms-cache 2048  --max-inflight 8
  --public-url https://terraserve.io/demo/cos2023/wms

# and one environment variable, which matters more than it looks:
TERRASERVE_FGB_MAX_QUERY_FEATURES=2000000
--vector The data file: a FlatGeoBuf holding all 842,413 land-cover shapes. It carries a spatial index, which is what lets the server read just the piece you're looking at instead of loading the file.
--vec-style How to colour it for the picture view: a standard SLD that gives every land-cover class its own fill.
--src-crs The map projection the data is stored in (Portugal's national grid, EPSG:3763).
--name What the layer is called. This one name has to match in four places: the WMS layer, the vector-tile source, the style, and the viewer URL.
--mvt-style A second style, for the vector-tile view the browser draws itself. Same data, different renderer, so it needs its own colours.
--mvt-min-feature-px 8 When zoomed out, skip any shape smaller than 8 pixels. That's far less to send, and you couldn't see it anyway.
--pmtiles A pre-baked archive of the common zoom levels. A request in that range is a straight read off disk: about 5 ms, no drawing at all.
--mvt-cache 0 No in-memory tile cache needed on top of the archive: a read from it is already a few milliseconds, and the operating system keeps the hot parts in RAM for free.
--wms-cache 2048 Remember recently-drawn pictures (up to 2 GB) so an identical repeat costs nothing. This is what makes panning back over ground you have already seen instant.
--max-inflight 8 Draw at most 8 maps at once: one per CPU core. Drawing is CPU-bound, so allowing more would just make everything queue behind everything else.
--public-url The public address to advertise to GIS clients. The server sits behind a proxy, and QGIS takes the address for every follow-up request from this value. Get it wrong and QGIS lists the layer but draws nothing.
TERRASERVE_FGB_MAX_QUERY_FEATURES A safety limit on how many shapes one request may decode, raised above this layer’s 842,413. It's a correctness setting, not a speed one: left at its default, a wide request quietly stops early and whole regions go missing behind a perfectly normal-looking response.

Measured on the live server: 75 MB of memory per copy, 8 s to start. Map tiles take about 150 ms each the first time and 5 ms once cached; the pre-baked zoom levels come back in about 5 ms. The honest exception: asking for the entire country as one image, which QGIS does if you hit "zoom to full extent", takes around 35 s the first time, because there's no pre-simplified copy to fall back on. Every repeat after that is instant.

Source & attribution. Data: Direção-Geral do Território (DGT), Carta de Uso e Ocupação do Solo (COS), Série 2, 2023, Portugal Continental. DGT publishes this same layer in their Visualizador SMOS, served from their own GeoServer. That's the same GeoServer this dataset was benchmarked against.