QGIS Python Version Compatibility Guide
QGIS ships with a strictly version-locked Python interpreter. The bundled Python minor version changes with each major release, and you cannot safely swap it for a system Python, conda environment, or standalone installer without breaking compiled qgis.core and qgis.gui bindings. Always match external packages to the exact minor version QGIS provides.
| QGIS Release Range | Bundled Python | Compatibility Notes |
|---|---|---|
| 3.16–3.22 | 3.9.x | Legacy LTR. Requires pip install --ignore-installed. |
| 3.24–3.30 | 3.9.x → 3.10.x | Transition builds. macOS Homebrew may ship mismatched wheels. |
| 3.32–3.38 | 3.10.x | Stable baseline. C-extensions must target the 3.10 ABI. |
| 3.40+ | 3.12.x | Requires updated C-extensions. PyQt6 migration begins. |
Rule of thumb: Never assume a Python wheel built for your OS system Python will work inside QGIS. Verify the ABI tag (cp39, cp310, cp312) matches the QGIS runtime before installing.
Why Version Locking Matters
The QGIS API Architecture relies on SIP-generated Python bindings compiled against a specific Python ABI and Qt/PyQt version. When Python’s minor version changes, the C-extensions in qgis._core become binary-incompatible. Mixing external Python installations with QGIS plugins typically triggers ImportError: DLL load failed or ModuleNotFoundError: qgis.
Verify Your Active Environment
Run this in the QGIS Python Console (Plugins > Python Console) to confirm version alignment:
import sys
import qgis.core
print(f"QGIS Python: {sys.version_info.major}.{sys.version_info.minor}")
print(f"QGIS Core Path: {qgis.core.__file__}")
if sys.version_info < (3, 9):
raise RuntimeError("Python < 3.9 is incompatible with QGIS 3.16+")
Safe Dependency Installation
Follow the PyQGIS Fundamentals & Environment Setup workflow to treat QGIS as a self-contained runtime. Add third-party libraries without breaking bindings:
- Use the bundled
pip: QGIS 3.22+ includespipin the console.
import subprocess, sys
subprocess.check_call([sys.executable, "-m", "pip", "install", "requests"])
- Windows: Always run external scripts via
python-qgis.bat(located in the QGIS install folder). This launcher setsPYTHONHOME,PYTHONPATH, andQT_PLUGIN_PATHautomatically. - Linux/macOS: Invoke
qgis --code script.pyor source the officialqgis.shenvironment script. Never manually exportPYTHONPATHto system directories.
Recover from ABI Mismatches
If you encounter ImportError: cannot import name 'QgsApplication', DLL load failed, or silent crashes after installing packages:
- Clear corrupted packages: Delete manually copied folders in QGIS’s user profile:
- Windows:
%APPDATA%\QGIS\QGIS3\profiles\default\python\ - Linux/macOS:
~/.local/share/QGIS/QGIS3/profiles/default/python/
- Force reinstall via QGIS pip: Open the Python Console and run:
import subprocess, sys
subprocess.check_call([sys.executable, "-m", "pip", "install", "--force-reinstall", "package_name"])
- Use OSGeo4W for geospatial wheels: For GDAL, Fiona, or Shapely, install via the OSGeo4W installer. It compiles binaries against the exact Python version and MSVC runtime QGIS expects, preventing C-extension segfaults.
- Avoid
venvfor QGIS plugins: CopyingqgisandPyQt5into a virtual environment only works temporarily and breaks on updates. Reserve external environments for pure data processing (pandas, rasterio) that runs outside the QGIS process.
Deployment Checklist
- ✅ Match your plugin’s
metadata.txtqgis_minimum_versionto the Python version you tested. - ✅ Never hardcode
sys.path. Useos.environ["PYTHONPATH"]only when spawning external processes. - ✅ Audit C-extensions before upgrading QGIS. Python 3.10+ drops legacy wheel formats and changes
str/byteshandling. - ✅ Keep
qgis.core,qgis.gui, andqgis.analysisimports strictly inside the bundled runtime.