Skip to content

What is PEP 703?

PEP 703: Making the Global Interpreter Lock Optional in CPython is the proposal that makes a no-GIL CPython build real. It adds a build configuration that removes the Global Interpreter Lock (GIL), the mutex that lets only one thread execute Python bytecode at a time, producing the free-threaded Python interpreter.

The PEP was authored by Sam Gross at Meta. The Steering Council announced intent to accept in July 2023 and formally accepted the PEP on 24 October 2023 with a phased rollout: experimental in 3.13, officially supported under PEP 779: Criteria for supported status for free-threaded Python in 3.14, with any default-build switch deferred for years.

How PEP 703 removes the GIL

CPython gains a build flag, --disable-gil, that compiles an interpreter without the GIL. Because removing the lock changes the Python object header (to support biased reference counting), the free-threaded build is not ABI-compatible with the standard build. C extensions must be rebuilt, and wheels are published under a separate ABI tag carrying a t suffix.

The free-threaded build is a separate artifact. A standard CPython install keeps the GIL. A free-threaded install removes it. Both can coexist on the same machine; uv and other version managers install them side by side.

Why remove the GIL

The GIL serializes Python bytecode across threads, so threaded CPU-bound Python code does not scale with cores. Existing workarounds, especially multiprocessing and GIL-releasing C extensions, add process overhead or runtime complexity without helping CPU-bound pure-Python code. Removing the GIL lets threaded Python code run in parallel on multiple cores without leaving the Python runtime.

Use free-threaded Python today

Python 3.13 shipped the free-threaded build as experimental. Python 3.14 moved it to officially supported under the criteria set by PEP 779. The default Python build still ships with the GIL on every supported version; the free-threaded build is an opt-in variant.

To install and run the free-threaded build with uv, see Try Free-Threaded Python with uv or How to use free-threaded Python in a uv project.

Detect a free-threaded build

A free-threaded build announces itself in several places:

  • Binary name. The executable is named with a t suffix, for example python3.13t or python3.14t.
  • Build configuration. sysconfig.get_config_var("Py_GIL_DISABLED") returns 1. The Python docs call this the recommended check when a decision depends on the build.
  • Runtime GIL state. sys._is_gil_enabled() (added in 3.13) returns False when the GIL is actually off. The GIL can be re-enabled at runtime via PYTHON_GIL=1 or the -X gil=1 flag, and importing a C extension that has not declared free-threaded support turns it back on automatically, so the runtime check can disagree with the build-time one.

Weigh the tradeoffs

The switching decision turns on a few costs:

  • Single-threaded slowdown. Free-threaded CPython runs roughly 10-15% slower on single-threaded workloads than the GIL build, because reference counting and other per-object operations need thread-safe variants.
  • C extension coverage. Each C extension has to declare free-threaded support and ship a wheel under the t ABI tag. Coverage across PyPI is uneven. Scientific packages ship free-threaded wheels on recent versions; niche or unmaintained packages often do not, and uv falls back to building from source in their absence.
  • Latent thread-safety bugs. The GIL hid many data races behind implicit bytecode-level atomicity. Pure-Python code that looked correct under the GIL may need explicit locks or atomics to be correct without it.

Learn More

Last updated on

Please submit corrections and feedback...