How to Install GDAL in CI Without Version-Mismatch Failures
GDAL is one of the hardest Python packages to install in CI: the Python binding must exactly match the system GDAL C library version, or the build fails.
The GDAL Python package binds to the system GDAL C/C++ library, and the binding version must match the installed libgdal version exactly. CI runners rarely have GDAL at all, and even when they do, a version skew between libgdal-dev and the pip package breaks the build. The reliable path is to install the system library first and pin the binding to its version.
Why it fails in CI
The GDAL Python binding builds against the system GDAL headers and calls gdal-config to discover the version. With no system GDAL installed, gdal-config is missing; with a mismatched version, the build compiles against the wrong API and fails. Pip alone cannot fix this - the C library has to be there first.
gdal-config not found/Could not find gdal-configduring the build.- Version mismatch:
pip install gdal==Xwhere X differs from the installedlibgdal. fatal error: gdal.h: No such file or directory- no GDAL dev headers.
Install it reliably
Install libgdal-dev (the system library and headers) first, read its version from gdal-config, then install the matching Python binding version. Pinning the binding to the system GDAL version is the key step.
# 1) System GDAL + headers
apt-get update && apt-get install -y libgdal-dev gdal-bin build-essential
# 2) Read the system version and pin the binding to it
export GDAL_VERSION=$(gdal-config --version)
pip install "GDAL==${GDAL_VERSION}.*"Cache & speed
Installing libgdal-dev pulls many geospatial dependencies and is slow - bake GDAL into a custom runner image (or use an official GDAL Docker image) instead of apt on every job. Cache ~/.cache/pip for the binding.
- uses: actions/cache@v4
with:
path: ~/.cache/pip
key: pip-gdal-${{ hashFiles('requirements*.txt') }}Common errors
| Error | Cause | Fix |
|---|---|---|
| gdal-config not found | No system GDAL | apt-get install libgdal-dev |
| gdal.h: No such file or directory | No GDAL dev headers | apt-get install libgdal-dev |
| Version mismatch on build | Binding != libgdal version | Pin GDAL==$(gdal-config --version) |
| Slow apt every job | Reinstalling GDAL each run | Bake into image / use GDAL container |
Key takeaways
- Install libgdal-dev first; the binding cannot build without it.
- Pin the Python GDAL binding to gdal-config --version exactly.
- Bake GDAL into the image or use a GDAL container - apt is slow.