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 RangeBundled PythonCompatibility Notes
3.16–3.223.9.xLegacy LTR. Requires pip install --ignore-installed for reinstalls.
3.24–3.283.9.xStable series. C-extensions must target the 3.9 ABI.
3.30–3.323.10.xTransition builds. macOS Homebrew may ship mismatched wheels.
3.34–3.363.12.xRequires updated C-extensions. PyQt5 remains the default.
3.38–3.443.12.xIncludes the 3.40 and 3.44 LTRs — the final 3.x (Qt5/PyQt5) series.
4.0+3.12.x+Qt6/PyQt6 generation. Confirm with sys.version inside the QGIS Console; release notes may revise this.

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 any C-extension package.

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 version: {qgis.core.Qgis.QGIS_VERSION}")
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:

  1. Use the bundled pip: QGIS 3.22+ includes pip in the console. Open the Python Console and run:
import subprocess, sys
subprocess.check_call([sys.executable, "-m", "pip", "install", "requests"])
  1. Windows: Always run external scripts via python-qgis.bat or python-qgis-ltr.bat (located in the QGIS bin folder). This launcher sets PYTHONHOME, PYTHONPATH, and QT_PLUGIN_PATH automatically.
  2. Linux/macOS: Invoke scripts using the QGIS-bundled Python executable directly. Never manually export PYTHONPATH to system Python directories when targeting the QGIS runtime.

Recover from ABI Mismatches

If you encounter ImportError: cannot import name 'QgsApplication', DLL load failed, or silent crashes after installing packages:

  1. 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/
  2. 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"])
  1. Use OSGeo4W for geospatial wheels (Windows): 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.
  2. Avoid venv for QGIS plugins: Copying qgis and PyQt5 into 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.txt qgisMinimumVersion to the QGIS version you tested against.
  • Never hardcode sys.path. Use os.environ["PYTHONPATH"] only when spawning external processes.
  • Audit C-extensions before upgrading QGIS. A Python minor version bump (e.g., 3.9 → 3.12) requires recompiling or sourcing new ABI-compatible wheels for every C-extension dependency.
  • Keep qgis.core, qgis.gui, and qgis.analysis imports strictly inside the bundled runtime.

Frequently Asked Questions

Which Python version does QGIS 3.34 LTR ship with? QGIS 3.34 ships with Python 3.12.x, and that interpreter is shared across the whole 3.34–3.36 range. Any C-extension you install for use inside QGIS must therefore target the cp312 ABI. Run sys.version_info in the QGIS Python Console to confirm the exact minor version on your install.

Can I upgrade the Python interpreter that QGIS uses? No. The bundled Python is version-locked because the SIP-generated qgis._core and qgis._gui bindings are compiled against one specific Python ABI and Qt build. Swapping in a system Python, conda environment, or newer installer breaks those bindings and produces ImportError: DLL load failed or ModuleNotFoundError: qgis. Treat QGIS as a self-contained runtime instead.

How do I check whether a wheel is compatible with my QGIS install? Match the wheel's ABI tag to the QGIS Python minor version: cp39 for QGIS 3.16–3.28, cp310 for 3.30–3.32, and cp312 for 3.34 and later. A wheel built for your operating system's system Python will not necessarily match, so verify the tag before installing any C-extension package. Pure-Python packages with no compiled code are generally safe across minor versions.

Why do I get an ABI mismatch after upgrading QGIS? A QGIS upgrade that bumps the Python minor version (for example 3.9 to 3.12) invalidates every previously installed C-extension, because those binaries were compiled against the old ABI. Reinstall the affected packages with pip install --force-reinstall from the bundled pip, or source new ABI-compatible wheels. Pure data-processing libraries running outside the QGIS process in their own environment are unaffected.

Should I use a virtual environment for QGIS plugin dependencies? Not for code that imports qgis or PyQt5. Copying those bindings into a venv only works temporarily and breaks on the next QGIS update. Reserve virtual environments for pure data-processing dependencies such as pandas or rasterio that run outside the QGIS process, and let QGIS manage its own bundled packages.