Short answer
Productizing terrain analysis means converting the slope, aspect, hillshade, and watershed maps you currently make by hand, per project, into a single parameterised pipeline whose outputs are standard, documented, versioned, and reusable. The shift is organisational as much as technical: instead of a report folder that dies when the project ends, you build one terrain asset that every rerun improves, served as Cloud-Optimized GeoTIFFs through download or an API, with metadata that says exactly which DEM, CRS, resolution, and algorithm produced it. The hard parts are CRS and resolution discipline, honest metadata, and clean versioning — not the raster math.
From deliverable to product
A one-off terrain analysis looks like this: download a DEM, open QGIS, run the slope tool, style it, screenshot it into a report, ship the PDF. It answers one question once. Six months later a colleague needs the same slope layer for an adjacent site and starts from zero, possibly with different parameters, producing a subtly different result.
A terrain product is the same computation captured as a reusable system. Its defining properties:
- Parameterised, not manual. The DEM source, target CRS, resolution, and which derivatives to compute live in a config file, not in someone's click history.
- Standard outputs. Rasters are COGs; vectors are GeoPackage or vector tiles. No project-specific formats.
- Documented. Every output carries metadata describing its provenance and parameters.
- Versioned. Reruns produce a new version, not an overwrite, so results are reproducible and comparable over time.
- Accessible. Consumers reach it by download, API, or a styled web layer — not by emailing a file.
The pipeline, end to end
A defensible terrain pipeline has clear stages, each independently rerunnable.
1. Ingest and condition the DEM. Pull the source (SRTM, Copernicus DEM, a national lidar product) and immediately fix its spatial reference. This is the step most one-off workflows get wrong. Slope, aspect, and hillshade are only meaningful when horizontal and vertical units match, so reproject from geographic coordinates into a projected CRS with metric units:
gdalwarp -t_srs EPSG:25832 -tr 10 10 -r bilinear \
-of GTiff srtm_raw.tif dem_proj.tif
-tr 10 10 fixes a 10 m grid explicitly rather than inheriting whatever the source had; -r bilinear is the appropriate resampling for continuous elevation. If you compute slope on a DEM still in EPSG:4326, the run/rise ratio mixes degrees and metres and the values are simply wrong — typically off by the cosine-of-latitude factor.
2. Compute derivatives. Use gdaldem, which is scriptable and deterministic:
gdaldem slope dem_proj.tif slope.tif -compute_edges
gdaldem aspect dem_proj.tif aspect.tif -compute_edges
gdaldem hillshade dem_proj.tif hillshade.tif -az 315 -alt 45
gdaldem slope uses the Horn (1981) method by default — record that in metadata, because the Zevenbergen–Thorne alternative gives slightly different values. -compute_edges avoids a NoData border one pixel wide. Hillshade parameters (azimuth 315, altitude 45) are cartographic choices worth pinning so every run looks consistent.
3. Convert to Cloud-Optimized GeoTIFF. A COG carries internal tiling and overviews so clients can read a window or a low-resolution view over HTTP without downloading the whole file:
gdal_translate slope.tif slope_cog.tif \
-of COG -co COMPRESS=DEFLATE -co OVERVIEW_RESAMPLING=AVERAGE
This single format choice is what lets the same output feed a download, a web map, and an API without re-export.
4. Vector derivatives where useful. Contours and watershed polygons travel better as vectors:
gdal_contour -a elev -i 10 dem_proj.tif contours.gpkg
Parameterise it
The whole pipeline should run from a small config so a new site is a new config file, not a new manual session:
job: site_alpha
dem_source: copernicus_30m
target_crs: EPSG:25832
resolution_m: 10
derivatives: [slope, aspect, hillshade, contours]
hillshade: { azimuth: 315, altitude: 45 }
contour_interval_m: 10
version: 3
A thin script reads this, runs the GDAL steps, and writes outputs into a versioned path (site_alpha/v3/). Now reruns are trivial, parameters are explicit, and two sites are guaranteed comparable.
Metadata and versioning
A terrain derivative is untrustworthy without provenance. At minimum, store alongside each output:
- Source DEM identity and acquisition/publication date
- CRS and resolution
- Algorithm and exact parameters (e.g. "slope, Horn method, degrees")
- Processing date and pipeline version
- Licence and redistribution terms of the source
Embed what you can in the GeoTIFF tags and keep a sidecar (a STAC item is the natural choice for raster products, giving you a standard JSON describing the asset, its bbox, datetime, and properties). Version by immutable directories or object-store prefixes: v1, v2, v3 never overwrite each other, so a client who cited v2 can still fetch exactly what they saw.
Exposing it
Match the access method to the consumer:
- Download of the COG for analysts who pull it into their own GIS.
- An API for programmatic access — OGC API – Features for vector derivatives, OGC API – Coverages or a simple tile/COG endpoint for rasters. Define who calls it and what question it answers before building it.
- A styled web layer for decision-makers who just need to see slope or hazard zones.
The COG plus a STAC catalogue covers most of this with off-the-shelf tooling.
Common pitfalls and why they happen
- Computing slope in geographic coordinates. Degrees of latitude and longitude are not equal distances, and vertical is in metres, so the gradient is nonsense. It happens because the DEM "just worked" visually and nobody checked units.
- Calling a folder a product. A directory of TIFFs with no metadata or version cannot be reproduced or trusted; the discipline is what makes it a product, not the file count.
- Overwriting outputs. Without versioning, a rerun silently invalidates anything that referenced the old result.
- Ignoring source licence. Some DEMs restrict redistribution; building a public product on them creates a legal problem discovered late.
Validation
- Spot-check slope against a hand-computed gradient on a known ridge — gross unit errors show up immediately.
- Confirm the output CRS and resolution match the config, not the source default.
- Verify the COG is valid (
gdalinfoshows overviews and tiling; therio cogeo validatetool or GDAL's COG check confirms structure). - Re-run the same config and diff the outputs — a product should reproduce bit-for-bit given the same inputs.
Bathyl perspective
We treat terrain analysis as an asset to be maintained, not a deliverable to be shipped and forgotten. A parameterised pipeline with COG outputs, honest metadata, and immutable versions means each update sharpens one durable product, keeps the science traceable, and lets the next person reuse the result instead of rebuilding it.
Related reading
- Slope, Aspect, and Hillshade From DEM Data
- Why DEM Slope Values Are Wrong in Geographic Coordinates
- Building a GIS Knowledge Base
- Spatial data products