Short answer
There is no single "best" GIS for terrain analysis — there is a best tool per task and per scale. For everyday slope, aspect, hillshade and contour derivation, QGIS driving GDAL is hard to beat and free. For rigorous hydrology and geomorphometry, reach for GRASS GIS or SAGA. For repeatable batch processing of many DEM tiles, call GDAL (or PyQGIS / rasterio) from a script. For supported, integrated enterprise workflows, ArcGIS Pro earns its licence. And for continental-scale DEMs you do not want to download, Google Earth Engine runs the analysis in the cloud. The discipline matters more than the brand: know your DEM's CRS, vertical units and edge behavior before you compute anything.
The thing that breaks more results than software choice
Every terrain derivative depends on the relationship between horizontal and vertical units. Slope is arctan(rise/run), so if your DEM is in a geographic CRS (EPSG:4326) the horizontal "run" is in degrees while the "rise" is in metres — the ratio is meaningless and slopes come out wildly wrong, varying with latitude. The fix is to reproject to a projected CRS in metres first:
gdalwarp -t_srs EPSG:32633 -r bilinear -tr 30 30 dem_4326.tif dem_utm.tif
GDAL's gdaldem slope offers a -s scale factor (e.g. -s 111120) as a workaround for geographic DEMs, but reprojecting is cleaner. Equally, confirm the vertical unit: a DEM in feet processed as if metres gives a 3.28× slope error. This single class of mistake — mixed units, wrong CRS — corrupts more terrain analyses than any tool limitation.
The contenders
QGIS + GDAL — the default free stack
QGIS's terrain tools are largely thin wrappers over the same gdaldem engine, plus its own Slope, Aspect, Hillshade and Ruggedness index algorithms under Processing → Raster terrain analysis. The GDAL hillshade and slope use the Horn (1981) 3×3 neighbourhood method, the standard for DEMs. You get interactive QA, styling and the full Processing toolbox (which also exposes GRASS and SAGA). Best for analyst-led, visual, mixed work.
GDAL command line — repeatability
gdaldem is the engine: slope, aspect, hillshade, roughness, TRI, TPI, color-relief. Scriptable, fast, and identical every run:
gdaldem hillshade -z 1.5 -az 315 -alt 45 -compute_edges dem_utm.tif hs.tif
gdaldem slope -compute_edges -p dem_utm.tif slope_pct.tif
gdaldem aspect -zero_for_flat dem_utm.tif aspect.tif
Note -compute_edges, which avoids a NoData ring on tile borders, and -z for vertical exaggeration. Pair with gdalbuildvrt to mosaic tiles virtually before processing. This is the right layer for any job that runs more than once.
GRASS GIS — hydrology and rigor
GRASS has the deepest, most peer-reviewed terrain hydrology: r.watershed (multiple-flow-direction accumulation that handles depressions without explicit filling), r.fill.dir, r.stream.extract, r.geomorphon (a robust landform classifier), and r.slope.aspect with full curvature outputs. Its location/mapset model enforces a consistent CRS — a feature, not friction, for serious projects.
SAGA — geomorphometry toolbox
SAGA shines for derived terrain attributes: Topographic Wetness Index (TWI), Terrain Ruggedness Index, Topographic Position Index, Channel Network, Catchment Area (multiple flow), Sky View Factor, and sink-filling (Planchon & Darboux, Wang & Liu). Reachable from QGIS Processing.
ArcGIS Pro — supported and integrated
The Spatial Analyst Surface and Hydrology toolsets (Slope, Aspect, Hillshade, Fill, Flow Direction, Flow Accumulation, Watershed, Viewshed 2), plus ModelBuilder for visual pipelines and arcpy for scripting. Strong 3D (terrain datasets, LAS/point-cloud handling) and enterprise data management. The trade-off is licensing cost and vendor lock-in; the gain is support and a coherent, documented toolbox.
Google Earth Engine — planetary scale
When the DEM is SRTM, Copernicus GLO-30, ALOS or NASADEM, ee.Terrain.slope(), .aspect() and .hillshade() run server-side over arbitrarily large areas with no download. Best for regional screening; less suited to bespoke high-precision local work.
Choosing by task
| Task | First choice | Why |
|---|---|---|
| Slope/aspect/hillshade, one-off | QGIS | Interactive, free, Horn method built in |
| Batch derivatives over many tiles | GDAL / PyQGIS | Scripted, identical every run |
| Watersheds, flow accumulation | GRASS r.watershed / ArcGIS Hydrology | Rigorous depression handling |
| TWI, landforms, ruggedness | SAGA / GRASS r.geomorphon | Rich geomorphometry library |
| Viewsheds, line-of-sight | GRASS r.viewshed / ArcGIS Viewshed 2 | Mature visibility algorithms |
| Continental DEM analysis | Google Earth Engine | No download, server-side |
| Enterprise, supported, 3D | ArcGIS Pro | Integrated toolbox + support |
A reproducible pipeline example
A defensible terrain workflow for a project tile, fully scripted:
- Audit & reproject: check CRS and vertical unit, then
gdalwarpto a metric CRS at a fixed resolution. - Mosaic if tiled:
gdalbuildvrt project.vrt tile_*.tif. - Fill or flag sinks (GRASS
r.fill.diror SAGA Fill Sinks) — only where hydrology requires it; over-filling destroys real basins. - Derivatives:
gdaldemfor slope/aspect/hillshade with-compute_edges; GRASS/SAGA for hydrology and TWI. - QA against known landforms: ridges, valleys and a known peak/saddle; check for striping or DEM-stitch artefacts.
- Publish with metadata: record source DEM, resolution, CRS, algorithm and parameters.
Version the script. A clicked-through GUI session cannot be audited six months later; a logged gdaldem command can.
Common pitfalls and why they happen
- Computing slope on a geographic DEM. Degrees-over-metres gives latitude-dependent nonsense; reproject to metres first.
- Wrong vertical unit. A feet DEM treated as metres scales every slope by 3.28; check the metadata, not the look.
- NoData edge artefacts. Forgetting
-compute_edgesleaves a border ring that contaminates downstream flow analysis. - Over-filling sinks. Aggressive depression removal erases genuine closed basins and karst features; fill only as much as the hydrology model needs.
- Wrong resampling on reprojection. Use bilinear or cubic for continuous elevation; nearest neighbour stair-steps the surface and ruins derivatives.
- Mixing DEM sources at different resolutions without resampling to a common grid, producing seams in derivatives.
Quality and validation
- Confirm CRS, horizontal units and vertical units before any derivative.
- Inspect hillshade for striping, banding or stitch lines that reveal DEM defects.
- Validate slope/aspect against a known landform and against an independent DEM where possible.
- For hydrology, check that extracted streams follow real valleys and that watersheds close.
- Document source DEM, version, resolution, algorithm and every parameter in the output metadata.
Bathyl perspective
We are deliberately tool-agnostic: QGIS and GDAL for the bulk of terrain derivation, GRASS and SAGA for hydrology and geomorphometry, ArcGIS Pro where a client's stack demands it, and Earth Engine for regional scale. What we are not agnostic about is method — the CRS, vertical units, edge handling and parameters are recorded so any terrain product can be reproduced and audited.
Related reading
- QGIS vs ArcGIS Online
- QGIS vs Google Earth Engine for Remote Sensing
- Shapefile vs GeoPackage vs GeoJSON
- GIS and spatial analysis