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.
- Validate inputs. Run
gdalinfo/ogrinfoand assert the expected CRS, geometry type, and band count; fail loudly if a delivery differs. - Stage, don't mutate. Read from a read-only source directory and write to an output directory, so a rerun starts from clean source.
- One CRS decision. Reproject everything to the project CRS at ingest; downstream steps then assume it.
- Process the VRT. Mosaic with
gdalbuildvrt, then warp/translate the VRT. - Compress and tile outputs. Write Cloud Optimized GeoTIFFs (
-of COG -co COMPRESS=DEFLATE) so they stream well and stay small. - Validate outputs. Check feature counts, extent, geometry validity, and that NoData survived. For vectors,
ST_IsValidonce they are in PostGIS; for rasters, recompute statistics and compare against expectations. - 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 -sofeature 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_IsValidin PostGIS, orogr2ogr ... -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_srsonly labels the data;gdalwarp -t_srsactually moves it. Assigning a CRS to force alignment, when the coordinates are truly in another system, silently corrupts positions. - Schema drift in batches. Looping
ogr2ogrover 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
- ogr2ogr for Format Conversion
- gdalwarp for Raster Reprojection
- Shapefile vs GeoPackage vs GeoJSON
- PostGIS for Spatial Data Management
- Spatial data products