Short answer

GDAL/OGR is the engine under almost every GIS application (QGIS, ArcGIS, PostGIS, and most web stacks read and write through it), and using it directly turns one-off desktop operations into commands you can rerun, version, and audit. The value is not that it is a command line — it is that a command is documentation: gdalwarp -s_srs EPSG:4326 -t_srs EPSG:32631 -r bilinear in.tif out.tif says exactly what happened, forever. For a team, that reproducibility is the difference between a result you can defend and one you have to recreate from memory.

The four commands that cover most work

You can do the large majority of day-to-day data engineering with four tools. Knowing them well beats knowing twenty shallowly.

gdalinfo / ogrinfo — look before you touch

Never process data you have not inspected. gdalinfo reports CRS, extent, pixel size, band count, data type, NoData value, and statistics:

gdalinfo -stats dem.tif | grep -i -E "Coordinate|Pixel|NoData|Type|Min|Max"
ogrinfo -so -al parcels.gpkg parcels   # summary: CRS, geom type, feature count, fields

The data type and NoData value matter: a Float32 DEM with NoData -9999 will produce garbage statistics if you forget the NoData flag, and an Int16 raster cannot hold elevations interpolated to fractions of a metre.

gdalwarp — reproject and resample rasters

gdalwarp -s_srs EPSG:4326 -t_srs EPSG:32631 \
  -r bilinear -tr 10 10 -tap \
  -dstnodata -9999 -of COG \
  -co COMPRESS=DEFLATE -co PREDICTOR=2 \
  srtm_wgs84.tif srtm_utm31n.tif

Key choices: resampling must match the data — bilinear/cubic for continuous surfaces (DEM, imagery), near for categorical rasters (land-cover classes) so values are never averaged into nonexistent classes. -tr sets output resolution, -tap aligns to a clean grid for mosaicking, and -dstnodata preserves masking through the reprojection.

ogr2ogr — convert, reproject, filter vectors

# Shapefile -> GeoPackage, reproject, fix to multipolygon, filter
ogr2ogr -f GPKG faults.gpkg faults.shp \
  -t_srs EPSG:2154 -nlt PROMOTE_TO_MULTI \
  -where "confidence >= 2" -nln faults_clean

-nlt PROMOTE_TO_MULTI avoids the classic "mixed single/multi geometry" failure when writing to formats that want one type per layer. -where pushes the filter into the read so you never materialise rows you discard.

gdalbuildvrt — batch without duplicating data

A virtual raster is an XML index over many files that GDAL treats as one mosaic. Process the VRT once instead of looping:

gdalbuildvrt tiles.vrt *.tif
gdalwarp -t_srs EPSG:3857 -r cubic -of COG tiles.vrt mosaic_3857.tif

This is dramatically cheaper than warping each tile and merging, and it keeps the source tiles untouched.

Loading straight into PostGIS

ogr2ogr writes to PostGIS as a destination, which makes it the bridge between files and a spatial database:

ogr2ogr -f PostgreSQL \
  PG:"host=db dbname=geo user=gis" \
  boreholes.gpkg \
  -nln geology.boreholes \
  -t_srs EPSG:2154 \
  -lco GEOMETRY_NAME=geom -lco FID=id -lco SPATIAL_INDEX=GIST \
  -nlt POINT

The layer-creation options (-lco) set the geometry column name, primary key, and spatial index up front so the table is queryable immediately. Reprojecting on import (-t_srs) means everything lands in one project CRS.

A reproducible pipeline pattern

The point of GDAL for a team is not heroic one-liners; it is a small, reviewable script that turns raw deliveries into clean products the same way every time.

  1. Validate inputs. Run gdalinfo/ogrinfo and assert the expected CRS, geometry type, and band count; fail loudly if a delivery differs.
  2. Stage, don't mutate. Read from a read-only source directory and write to an output directory, so a rerun starts from clean source.
  3. One CRS decision. Reproject everything to the project CRS at ingest; downstream steps then assume it.
  4. Process the VRT. Mosaic with gdalbuildvrt, then warp/translate the VRT.
  5. Compress and tile outputs. Write Cloud Optimized GeoTIFFs (-of COG -co COMPRESS=DEFLATE) so they stream well and stay small.
  6. Validate outputs. Check feature counts, extent, geometry validity, and that NoData survived. For vectors, ST_IsValid once they are in PostGIS; for rasters, recompute statistics and compare against expectations.
  7. Log the commands. The script itself, in version control, is the provenance record.

Validation and QA

  • Round-trip a sample. Reproject a small clip and a known control point; confirm the point lands where it should before running the full batch.
  • Count before and after. ogrinfo -so feature counts and raster extents should change only in ways you intended. A dropped feature count after a convert usually means a geometry-type or encoding failure that was swallowed.
  • Check geometry validity. Self-intersections and ring-order problems survive conversion silently; validate explicitly (ST_IsValid in PostGIS, or ogr2ogr ... -makevalid).
  • Exit codes, not file existence. A produced output file does not mean success — GDAL can write a partial result on warning. Check the return code in scripts and treat warnings as signals.

Common pitfalls and why they happen

  • Averaging categories. Using bilinear on a land-cover or class raster invents intermediate values that mean nothing. It happens because bilinear is the habit from imagery work; categorical data needs near.
  • Assigning vs transforming CRS. gdal_edit.py -a_srs only labels the data; gdalwarp -t_srs actually moves it. Assigning a CRS to force alignment, when the coordinates are truly in another system, silently corrupts positions.
  • Schema drift in batches. Looping ogr2ogr over deliveries assumes identical fields; one file with a renamed column or different geometry type breaks the load or, worse, drops data. Inspect before batching.
  • Uncompressed, untiled outputs. Default GeoTIFFs are large and slow over a network; teams notice only when the web map crawls. Add compression and COG tiling at write time.
  • Forgetting NoData. Statistics, hillshades, and analyses computed without the NoData flag fold the fill value into the result, skewing everything.

Bathyl perspective

We reach for GDAL when GIS stops being a series of clicks and starts being infrastructure that has to survive new data, new analysts, and new outputs. The aim is not cleverness but a pipeline whose every step is legible in a script — so a colleague can read how a product was made and rerun it without guessing.

Related reading

Sources