Home -> Docs -> CLI

Reference

The command line, end to end.

The terraserve binary is five subcommands. One of them, serve, runs the server and has a page of its own. The other four are one-shot tools: draw a PNG, bake a tile pyramid, inspect a coverage, answer a single request. This page covers all five, with a runnable example and the flags for each.

Overview

One binary, five subcommands. Everything below runs the same way: as terraserve <command> [flags], or inside Docker as docker run … terraserve <command> [flags] (mount your data at /data, exactly as in the quick start).

serve Run the live HTTP server: WMS, tiles, viewers. The everyday command; full flag reference on the Docs page.
render Render one window of a raster to a PNG. The engine core, no server.
build-pmtiles Bake a vector source into an offline .pmtiles tile pyramid (what the demos precompute for speed).
build-topology Build and report the shared-border topology of a coverage. A diagnostic; draws no tiles.
wms-handle Answer a single WMS request and write it to stdout. No server: for scripts and CI.

Every command prints its own flags with --help: terraserve build-pmtiles --help. The examples here use bare paths for readability; prefix them with /data/ when you run in a container.

serve

The live server: it publishes WMS, TMS, vector tiles and the built-in viewers. This is the command you run in production, and it has the most flags by far, data and styling, network, caching, vector tuning, multi-layer YAML. Its full reference lives on the Docs page. The shape is:

# one raster, as WMS + tiles
terraserve serve --cog ortho.cog.tif --style rgb.json \
  --host 0.0.0.0 --port 8080

# one vector layer (needs a style)
terraserve serve --vector roads.fgb --vec-style roads.style.json \
  --name roads --host 0.0.0.0 --port 8080

# many layers from a config
terraserve serve --config layers.yaml --host 0.0.0.0 --port 8080

The flags that matter for every deployment, --host 0.0.0.0 in a container, --public-url behind a proxy, --max-inflight as the memory ceiling, are covered with their pitfalls on the Docs.

render

The engine core with no server around it: read one window of a COG, warp and resample it into a grid, style it, write a PNG. It is the single-shot version of what serve does per WMS request, useful for a one-off image, a thumbnail, or a quick correctness check.

terraserve render \
  --cog cascais.cog.deflate.tif \
  --bbox -9.45,38.68,-9.38,38.72 --crs EPSG:4326 \
  --width 512 --height 512 \
  --resample bilinear \
  --style rgb.json \
  --out cascais.png
--cog PATH The source Cloud-Optimized GeoTIFF (local path or s3://…).
--bbox MINX,MINY,MAXX,MAXY The window to render, in --crs units. Values may be negative.
--crs CRS Output projection, e.g. EPSG:3857 or EPSG:4326.
--src-crs CRS The source projection the COG is in. Optional: defaults to EPSG:3763 (the bundled sample grid). Set it for a source in any other projection, e.g. EPSG:32629.
--width, --height N Output size in pixels.
--resample MODE nearest or bilinear.
--style PATH A style.json (mode rgb or pseudocolor). See the Styling guide.
--out PATH Where to write the PNG.

--src-crs defaults to the sample grid

When you omit --src-crs, the source is assumed to be in EPSG:3763, the projection of the bundled sample COG, so the reprojection to --crs is only correct for a source in that CRS. For anything else, pass it explicitly (--src-crs EPSG:32629). The --bbox is always given in --crs (output) units, whatever the source projection is.

build-pmtiles

Drawing vector tiles live is decode-bound: at low zoom a single tile has to read and generalize a large slice of the data, and that can take seconds. build-pmtiles pays that cost once, offline, into a static .pmtiles archive. Serving from the archive is then a byte-range read (milliseconds), not a render. This is exactly what the live demos precompute.

1. Bake the pyramid.

terraserve build-pmtiles \
  --vector roads.fgb \
  --vec-style roads.style.json \
  --name roads \
  --min-zoom 0 --max-zoom 14 \
  --out roads.pmtiles

2. Serve it. Point serve at the archive with --pmtiles; keep --vector pointed at the source so a zoom outside the baked range still falls through to a live draw.

terraserve serve \
  --vector roads.fgb --vec-style roads.style.json --name roads \
  --pmtiles roads.pmtiles \
  --host 0.0.0.0 --port 8080
--vector PATH The source to bake: a GeoPackage, FlatGeoBuf or GeoJSON.
--out PATH The .pmtiles archive to write.
--min-zoom, --max-zoom N Zoom range to generate, inclusive. Default 014. Higher max = more detail and a bigger archive (capped at z26).
--grid ID The tile grid to bake on: WebMercatorQuad (default), WorldCRS84Quad, the polar UPS grids, or a path to a custom OGC TileMatrixSet 2.0 JSON (a national grid). The archive is stamped with this grid; serve reads it only for matching-grid requests.
--vec-style PATH The vector style (marker + label symbolizer) for the layer.
--name NAME The layer name embedded in the tiles (the source-layer a client style targets). Match whatever you will serve and style this data under. Default vector.
--src-crs CRS The feature CRS. Default EPSG:4326; a GeoPackage's own CRS is auto-detected when unset.
--bbox W,S,E,N Limit baking to a WGS84 box. Default: the layer's own bounds.
--font PATH TrueType font for label text. Default DejaVuSans.ttf.
--tmpdir PATH Scratch directory for the streamed data section. Default: the system temp dir.

The baked tiles match a live render exactly

build-pmtiles runs the same encode and generalization pipeline as the live /mvt route, so an archived tile is byte-identical to the one serve would draw. That means the vector-tuning flags are shared: bake with the same generalization you would serve, --mvt-min-feature-px, --mvt-max-features, --mvt-dissolve, --keep-fields, --topology-simplify, all documented under Vector tuning. Keep --name the same across bake, serve and style, or a client's source-layer will not match.

build-topology

A diagnostic, not a renderer. It loads a polygon coverage (a GeoPackage, FlatGeoBuf or GeoJSON), snaps and builds its shared-border topology (the arcs that neighbouring polygons have in common), and prints a report. Nothing is served or stored. Use it to check a coverage is clean before you turn on serve --topology-simplify, which builds this same structure at startup to smooth every shared border gap-free (that serve-time build is GeoPackage-only).

terraserve build-topology \
  --vector coverage.gpkg \
  --snap-tolerance 0.01 \
  --verify

The report lists the feature, ring, arc and junction counts, how many arcs are shared versus on the outer boundary, the vertex count before and after snapping, any degenerate or non-finite geometry it dropped, and the total area delta from snapping. With --verify it also round-trips the topology back to polygons and reports how many features differ: 0 / N means the topology reproduces the input exactly.

--vector PATH The coverage to analyse: a GeoPackage, FlatGeoBuf or GeoJSON.
--layer NAME Which layer, if the GeoPackage has more than one (a FlatGeoBuf or GeoJSON is single-layer, so it is ignored there). Default: the auto-detected layer.
--snap-tolerance UNITS Snap tolerance in source-CRS units. Default 0.01. A fine value leaves an already-clean coverage untouched.
--verify After building, run the round-trip oracle and print the mismatch count. 0 = a perfect round-trip.

wms-handle

Answers one WMS request and writes the result to stdout, then exits, no server, no port. It handles GetMap (a PNG), GetCapabilities and exceptions (XML), for both WMS 1.1.1 and 1.3.0 including the EPSG:4326 axis flip. Handy for scripting a single render or sanity-checking WMS output in CI without binding a socket. Single COG only (no --config or --vector).

# capabilities document to a file
terraserve wms-handle --cog ortho.cog.tif --style rgb.json \
  --query 'SERVICE=WMS&VERSION=1.3.0&REQUEST=GetCapabilities' \
  > capabilities.xml

Swap REQUEST=GetMap (with LAYERS, CRS, BBOX, WIDTH, HEIGHT, FORMAT=image/png) and redirect to a .png to get a rendered map the same way.

--cog PATH The source COG (single layer; no --config or --vector).
--style PATH The style.json for the layer.
--query STRING The raw WMS KVP query, e.g. SERVICE=WMS&VERSION=1.3.0&REQUEST=GetMap&….

Full serve reference on the Docs ->