Short answer
QGIS, GDAL, and PostGIS are not competitors; they are three layers of one open pipeline, and you use them together once a project needs both reproducibility and shared, live data. Think of it as a stack: PostGIS is the system of record and server-side analysis engine, GDAL/OGR is the format-conversion, reprojection, and batch-processing workhorse, and QGIS is the visual workbench where you inspect, edit, style, and orchestrate. They interlock by design — QGIS Processing calls GDAL under the hood and connects natively to PostGIS — so the combination gives you a clickable front end, a scriptable engine, and a concurrent database without leaving the open-source world.
What each tool is actually for
PostGIS — the system of record and analysis engine
PostGIS (PostgreSQL + spatial extension) holds the authoritative data and runs analysis where the data lives. Many analysts edit the same layers under ACID transactions; spatial SQL (ST_Intersects, ST_Buffer, ST_Transform, ST_DWithin) executes server-side against GiST indexes; backends and tile servers query it live. Reach for it when data is shared, large, or feeding an application. (For the full case, see When to Use PostGIS Instead of Files.)
GDAL/OGR — the conversion and batch engine
GDAL (rasters) and OGR (vectors) are the libraries underneath nearly every GIS, exposed as command-line programs. They convert between 100+ formats, reproject, mosaic, clip, and process at scale, scriptably and reproducibly:
ogr2ogr— vector conversion, reprojection, SQL on the fly, loading into PostGIS.gdalwarp— raster reprojection, resampling, clipping.gdal_translate— raster format conversion and subsetting.gdaldem— slope, aspect, hillshade, roughness.gdalbuildvrt/gdal_merge— virtual mosaics and merging.
GDAL is where a workflow becomes a pipeline you can run again tomorrow on new data.
QGIS — the workbench
QGIS is the human interface: load and inspect layers, digitize and edit, build cartography, run analysis through the Processing Toolbox, and connect to PostGIS. Crucially, much of the Processing Toolbox is a graphical front end to GDAL and to algorithms from SAGA and GRASS. The QGIS GDAL dialogs even print the exact command they will run, so QGIS doubles as a way to learn GDAL.
How they fit together
The natural division of labour:
- Ingest and condition with GDAL. Reproject, validate, and convert incoming files to a common CRS and format, then load into PostGIS.
- Store and analyse in PostGIS. Hold the authoritative tables, run shared queries and heavy spatial joins server-side, enforce integrity.
- Inspect, edit, and present in QGIS. Connect to PostGIS, edit live, build derivatives through Processing (which calls GDAL), and produce maps and exports.
The handoffs are seamless because all three speak the same standards and the same GDAL core. A polygon you reproject with gdalwarp, store in PostGIS, and style in QGIS is the same geometry throughout.
Worked example: a reproducible terrain-to-database pipeline
You receive a folder of DEM tiles in mixed CRSs and need a single hillshade and slope product, stored where a team can use it.
1. Mosaic and reproject (GDAL):
gdalbuildvrt dem.vrt tiles/*.tif
gdalwarp -t_srs EPSG:25832 -r bilinear -tr 5 5 \
-dstnodata -9999 dem.vrt dem_25832.tif
A VRT avoids duplicating data; gdalwarp reprojects to ETRS89/UTM 32N at 5 m with bilinear resampling.
2. Derive terrain (GDAL):
gdaldem hillshade dem_25832.tif hillshade.tif -multidirectional -z 1
gdaldem slope dem_25832.tif slope.tif -p
3. Load vector context into PostGIS (OGR):
ogr2ogr -f PostgreSQL PG:"dbname=gis" boundaries.gpkg \
-t_srs EPSG:25832 -nln admin.boundaries -lco GEOMETRY_NAME=geom
4. Inspect, query, and present (QGIS): add the PostGIS connection, drag in admin.boundaries, load the GDAL-produced rasters, and run any further analysis through the Processing Toolbox. Because steps 1-3 are scripted, the whole product regenerates when new tiles arrive — and you can wrap the GDAL/OGR calls in a QGIS Processing model or a shell script so non-programmers can rerun it.
Click vs script: where to draw the line
- QGIS clicks for exploration, editing, ad-hoc analysis, and cartography — anything done once where seeing the result interactively matters.
- GDAL scripts (or Processing models) for anything repeatable: batch reprojection, nightly ingests, products that must regenerate when source data changes. Scripts are self-documenting and auditable; a sequence of mouse clicks is not.
Because QGIS GDAL dialogs reveal their command, you can prototype interactively, copy the command, and promote it to a script — a clean path from exploration to automation.
When you do not need all three
For a small, single-analyst project, QGIS alone (with a GeoPackage on disk) is the whole stack. Add GDAL when you start repeating processing or handling many files; add PostGIS when data becomes shared, large, or application-facing. Adopting the full stack prematurely adds operational overhead — database backups, connection management — for no benefit.
Common pitfalls and why they happen
- Scripting nothing. Doing every batch job by hand in QGIS makes products unreproducible and error-prone; the same task belongs in a GDAL script.
- Mixed CRSs across the stack. Conditioning everything to one projected CRS at the GDAL ingest stage prevents silent
ST_Intersectsfailures and misaligned rasters later. - Treating QGIS Processing as separate from GDAL. It is mostly a GDAL/SAGA/GRASS front end; not realizing this means people relearn the same operations twice.
- Forgetting spatial indexes after OGR loads. Without a GiST index, PostGIS queries the team runs from QGIS crawl, and people blame QGIS.
- Standing up PostGIS too early. A solo project rarely needs a server; the overhead outweighs the value.
QA checklist
- Standardize on one projected CRS at the GDAL ingest stage and verify it survives into PostGIS (
Find_SRID). - Capture repeatable processing as GDAL scripts or QGIS Processing models, not as undocumented clicks.
- Confirm GiST spatial indexes exist on PostGIS layers used interactively in QGIS.
- Validate geometry on load (
ST_IsValid/ QGIS Fix geometries). - Keep a clear record of which step produced each layer, so the pipeline is auditable end to end.
Bathyl perspective
We run this as one pipeline: GDAL conditions and reprojects incoming data, PostGIS holds the authoritative, indexed, shared copy, and QGIS is where people inspect, edit, and present it. Because QGIS Processing sits on the same GDAL core, interactive exploration converts cleanly into a scripted, rerunnable product. We add layers of the stack only when the workflow demands them, so a small job stays in QGIS and a shared programme gets the full database-backed pipeline.
Related reading
- When to Use PostGIS Instead of Files
- When to Use GeoPackage Instead of Shapefile
- When to Use Cesium Instead of a 2D Map
- GIS Stack Checklist Before a Project Starts
- GIS and spatial analysis