Fix GeoDjango "Could Not Find the GDAL Library" in Production and Docker
Fix the GeoDjango ImproperlyConfigured error could not find the GDAL library (tried gdal, GDAL...) on servers and in Docker: install GDAL, GEOS, and PROJ system packages, set GDAL_LIBRARY_PATH when needed, and match library versions to Django.
Problem statement
A GeoDjango project runs on your Mac but fails on the server or in Docker:
django.core.exceptions.ImproperlyConfigured: Could not find the GDAL library
(tried "gdal", "GDAL", "gdal3.9.0", "gdal3.8.0", ...). Is GDAL installed?
If it is, try setting GDAL_LIBRARY_PATH in your settings.
GeoDjango (django.contrib.gis) loads the GDAL, GEOS, and PROJ C libraries with ctypes at startup. They are system libraries, not Python packages, so pip install -r requirements.txt does not provide them. A slim Docker image or a fresh server has none of them until you install the OS packages.
- Debian or Ubuntu:
apt-get install -y gdal-bin libgdal-dev libgeos-dev libproj-dev(runtime only needsgdal-binorlibgdal3x,libgeos-c1v5,proj-bin). - Docker on
python:3.x-slim: add those packages in the Dockerfile before installing Python requirements. - If GDAL is installed in a non-standard place, set
GDAL_LIBRARY_PATHandGEOS_LIBRARY_PATHin settings. - Make sure the GDAL version is one your Django release supports; very new GDAL may need a newer Django.
- Check the same for GEOS: the related error is "Could not find the GEOS library".
Step-by-step solution
1. Check what is installed
gdal-config --version 2>/dev/null || echo "no gdal-config"
ldconfig -p | grep -E "libgdal|libgeos_c|libproj"
No libgdal.so lines means GDAL is missing. Django searches for library names it knows; a version it does not list will not be found automatically.
2. Install the system packages
On Debian 12 or Ubuntu 24.04:
sudo apt-get update
sudo apt-get install -y gdal-bin libgdal-dev libgeos-dev libproj-dev
The -dev packages are only needed to build Python packages that compile against GDAL (such as the GDAL Python bindings or rasterio from source). GeoDjango itself only needs the shared libraries.
3. Install in Docker
FROM python:3.12-slim
RUN apt-get update \
&& apt-get install -y --no-install-recommends gdal-bin libgeos-c1v5 libproj25 \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
Package names include version numbers (libproj25, libgeos-c1v5) that differ between Debian releases. gdal-bin depends on the right ones, so installing it alone often suffices. Images such as ghcr.io/osgeo/gdal include everything but are larger.
4. Point Django at the library if needed
When GDAL comes from a custom build, Conda, or a version Django does not know by name:
GDAL_LIBRARY_PATH = os.environ.get("GDAL_LIBRARY_PATH") # e.g. /usr/lib/x86_64-linux-gnu/libgdal.so.34
GEOS_LIBRARY_PATH = os.environ.get("GEOS_LIBRARY_PATH") # e.g. /usr/lib/x86_64-linux-gnu/libgeos_c.so.1
Use the full path to the shared object file. Find it with ldconfig -p | grep libgdal. Setting these to None lets Django search as usual.
5. Match versions
Each Django release supports a range of GDAL versions and lists the library names it tries. A brand-new GDAL may not be in the list of an older Django; either set GDAL_LIBRARY_PATH explicitly or upgrade Django. Also keep the PostGIS server version supported by your Django version; that is separate from the client libraries.
Explanation
django.contrib.gis.gdal and django.contrib.gis.geos wrap the C libraries through ctypes.util.find_library and a list of known file names. On macOS, Homebrew or Postgres.app usually installed them long ago, so development works. Production servers and slim containers start minimal, and the first import of a GIS model or field fails. Because the check runs when Django loads django.contrib.gis, the whole app fails at startup, not only geographic views.
Edge cases / notes
- Alpine. Alpine provides
gdalandgeospackages, but musl and version differences cause more trouble; Debian-based slim images are easier. - Managed platforms. Heroku needs the
heroku-geo-buildpackor a Docker deploy; Render and Railway work with a Dockerfile. - Raster support.
GDALRasterand raster fields need GDAL built with the right drivers; the Debian package includes common ones.
Next steps
- Set up the database side with Deploy GeoDjango With PostGIS in Production.
- For the PostGIS extension privilege error, see Fix Permission Denied to Create Extension.
- Choose a base image with Why Django Docker Builds Fail on Alpine.
FAQ
Can I pip install GDAL?
The GDAL Python package provides bindings but needs the system library to build and run. GeoDjango needs the system library itself.
Why does it work on my Mac?
Homebrew or Postgres.app installed GDAL and GEOS. The server or image does not have them.
Do I need libgdal-dev in production?
No, only to compile packages against GDAL. Runtime needs the shared libraries.
What is GDAL_LIBRARY_PATH for?
It tells Django exactly which shared library file to load when automatic search fails.