Short answer

A large raster workflow stops being a desktop problem and becomes an engineering problem once a single file no longer fits comfortably in RAM, or once the same operation must run across hundreds of tiles. The tools that scale are the GDAL command-line utilities (gdalwarp, gdal_translate, gdalbuildvrt, gdaladdo, gdaldem), the VRT virtual format, and the Cloud Optimized GeoTIFF (COG) layout. The discipline that scales is treating reprojection, compression, tiling, and overview generation as deliberate steps with recorded parameters, not as one-off menu clicks.

This guide covers the moves that matter most for terrain and Earth-observation data: building virtual mosaics, tuning gdalwarp for throughput, choosing creation options that actually shrink files, generating overviews, and running batches in parallel without corrupting outputs.

Why GDAL is the right layer for scale

GDAL reads and writes over 150 raster formats through a common abstraction, so a workflow written against gdalwarp works whether the source is a GeoTIFF, a NetCDF climate cube, a JPEG2000 satellite scene, or a remote COG over HTTP. Two properties make it suited to large jobs.

First, it streams. Most utilities read and write in blocks rather than loading the whole array, so memory use is bounded by the I/O cache (GDAL_CACHEMAX, default a few hundred MB) rather than by raster size. A 60,000 x 60,000 float32 DEM is roughly 13 GB uncompressed; GDAL processes it in tiles regardless.

Second, every command is a record. A line like gdalwarp -t_srs EPSG:3035 -tr 25 25 -r bilinear in.tif out.tif documents exactly what produced the output: target CRS, resolution, and resampling method. That reproducibility is the real reason to prefer the CLI over interactive GIS for production work — you can rerun it on next month's data and get a comparable result.

Virtual mosaics with VRT

The single most useful technique for many-tile datasets is the VRT (Virtual Raster). gdalbuildvrt mosaic.vrt tiles/*.tif writes a small XML file that references every source tile and presents them as one logical raster. No pixels are copied. You can then run gdaldem, gdalwarp, or gdal_translate against mosaic.vrt as if it were a single image.

# Index 2,000 elevation tiles into one virtual raster
gdalbuildvrt -resolution highest -r nearest dem_mosaic.vrt dem_tiles/*.tif

# Verify the virtual extent and resolution before processing
gdalinfo dem_mosaic.vrt

For tiles with overlapping edges or feathered seams, add -addalpha or supply a cutline. If tiles have inconsistent NoData, set -srcnodata/-vrtnodata so the mosaic does not paint black borders into the analysis area. Only materialize a real raster at the end of the pipeline, when you produce a deliverable.

Tuning gdalwarp for throughput

Reprojection is usually the slowest step. Four flags change the runtime profile substantially:

gdalwarp \
  -t_srs EPSG:3035 -tr 25 25 -r bilinear \
  -multi -wo NUM_THREADS=ALL_CPUS \
  -wm 2048 \
  -co TILED=YES -co COMPRESS=DEFLATE -co PREDICTOR=3 -co BIGTIFF=IF_SAFER \
  dem_mosaic.vrt dem_3035.tif
  • -multi with -wo NUM_THREADS=ALL_CPUS parallelizes the warp across cores.
  • -wm 2048 gives the warper 2 GB of working memory, reducing block thrash.
  • Choose resampling by data type: bilinear or cubic for continuous elevation, nearest for categorical rasters (land cover, geology codes) so you never invent class values that did not exist.
  • -tap (target-aligned pixels) snaps the output grid to a clean multiple of the resolution, which prevents half-pixel offsets when you later overlay layers — a common cause of stacks that look misaligned.

For elevation data, PREDICTOR=3 (floating-point predictor) typically compresses better than the default; for integer rasters use PREDICTOR=2.

Cloud Optimized GeoTIFFs

A COG is an ordinary GeoTIFF whose internal layout — tiled blocks plus embedded overviews, with the metadata at the front — lets a reader fetch just the bytes for a given window over an HTTP range request. That is what makes a 13 GB DEM usable directly from object storage by a web viewer or a cloud notebook.

gdal_translate dem_3035.tif dem_cog.tif \
  -of COG \
  -co COMPRESS=ZSTD -co PREDICTOR=3 -co BLOCKSIZE=512 \
  -co OVERVIEW_RESAMPLING=BILINEAR

The COG driver builds overviews and validates the layout automatically. You can confirm it with the validate_cloud_optimized_geotiff.py script shipped with GDAL. Serving COGs from S3, GCS, or a static host removes the need to pre-tile into thousands of small images for many web use cases.

Overviews and creation options

Overviews (reduced-resolution pyramids) are what keep a map responsive at low zoom. For non-COG outputs, build them explicitly:

gdaladdo -r average --config COMPRESS_OVERVIEW DEFLATE dem_3035.tif 2 4 8 16 32

Use average or bilinear for continuous data and nearest/mode for categorical rasters. Embedding overviews keeps a single file; external .ovr files are an option when you cannot rewrite the source.

On creation options generally: TILED=YES is almost always correct (striped TIFFs read poorly for windowed access), COMPRESS=DEFLATE or ZSTD with the right predictor gives lossless size reduction, and BIGTIFF=YES is mandatory above 4 GB or the write fails silently late in the job. For categorical data, COMPRESS=DEFLATE with PREDICTOR=2 and an internal color table is compact.

Worked example: country-scale slope map

Suppose you receive 1,400 SRTM-style elevation tiles in EPSG:4326 and need a slope raster in a national projected CRS for an erosion screening project.

# 1. Virtual mosaic (no pixels copied)
gdalbuildvrt srtm.vrt srtm_tiles/*.tif

# 2. Reproject and resample to 30 m in EPSG:3035, cache to disk once
gdalwarp -t_srs EPSG:3035 -tr 30 30 -tap -r bilinear \
  -multi -wo NUM_THREADS=ALL_CPUS -wm 2048 \
  -co TILED=YES -co COMPRESS=DEFLATE -co PREDICTOR=3 -co BIGTIFF=IF_SAFER \
  srtm.vrt dem_30m_3035.tif

# 3. Compute slope in degrees (Horn algorithm, edges handled)
gdaldem slope dem_30m_3035.tif slope_deg.tif -alg Horn -compute_edges \
  -co TILED=YES -co COMPRESS=DEFLATE -co PREDICTOR=3

# 4. Overviews for the web viewer
gdaladdo -r average slope_deg.tif 2 4 8 16 32

Two details matter geologically. Because the source is geographic (degrees), computing slope directly in EPSG:4326 would mix angular and linear units and bias results by latitude — reproject first. And -compute_edges avoids a one-pixel NoData frame on every tile boundary, which otherwise riddles a mosaic with seams.

Parallel batch processing

When the operation is per-tile and independent, parallelize across tiles rather than relying only on internal threading:

ls tiles/*.tif | parallel -j 8 \
  'gdalwarp -t_srs EPSG:3035 -tr 25 25 -r cubic \
   -co TILED=YES -co COMPRESS=ZSTD {} out/{/.}_3035.tif'

GNU parallel (or xargs -P) is reliable; the key rule is that each command writes a distinct output path. Never let two processes write the same file. For pipelines beyond a handful of steps, the Python bindings (osgeo.gdal) or the GDAL Python algorithm API give you error handling, logging, and conditional logic that shell loops cannot.

Common pitfalls and why they happen

  • Reprojecting on every run. gdalwarp is expensive. Reproject once into a canonical analysis CRS and cache the result; downstream steps read the cached raster. Teams that re-warp inside every job waste hours because the warp is buried in a script no one inspects.
  • Striped (non-tiled) GeoTIFFs. A striped TIFF must read whole rows, so windowed reads and overview builds crawl. Always pass TILED=YES.
  • Silent BIGTIFF failures. Classic TIFF caps at 4 GB. Without BIGTIFF=YES/IF_SAFER, a large write can corrupt near the end. Set it proactively for elevation mosaics.
  • Wrong resampling on categorical data. Bilinear-resampling a geology or land-cover raster invents fractional class codes that map to nonexistent units. Use nearest or mode.
  • Trusting exit codes alone. A command can succeed yet produce a raster with the wrong NoData, a shifted grid, or empty overviews. Inspect, do not assume.

Validation

Before a raster product goes into a map, report, or database, confirm:

  • gdalinfo -stats out.tif for extent, CRS, pixel size, data type, NoData, and min/max — outliers like a -9999 leaking into statistics reveal NoData errors.
  • gdalinfo reports overviews and block size; confirm tiling and pyramids exist.
  • Overlay against a trusted reference (a known coastline or a second DEM) to catch a shifted grid; -tap plus identical resolution should make grids coincide.
  • Spot-check edges and NoData regions, not just the clean center.

Bathyl perspective

We reach for GDAL pipelines when raster handling becomes infrastructure rather than a one-off task — when the same elevation, bathymetry, or satellite stack must be reprocessed as new acquisitions arrive. The aim is a small set of recorded commands that a future analyst can read, rerun, and trust, with the heavy reprojection done once and cached as COGs ready for both analysis and the web.

Related reading

Sources