The Global Interpreter Lock is the most-discussed limitation of CPython for thirty years. Every "why is threading slow in Python" article points to the GIL. Every workaround (multiprocessing, asyncio, C extensions that release the GIL) exists because of it. In October 2025, the Python 3.14 release made the free-threaded build officially supported via PEP 779, which depended on the architecture design of PEP 703 (Sam Gross, 2023). The GIL is now optional. This entry covers what changed, what the trade-offs are eight months in, the library compatibility state, how to install the no-GIL build, and the timeline toward "GIL off by default" in 2028-2030. Final entry in our Modern Python 2026 guide.

Key Takeaways

  • The free-threaded build is officially supported in Python 3.14 (PEP 779). It ships as a separate binary tagged 3.14t.
  • Single-threaded overhead is now 5-10%, down from 40% in the 3.13 experimental phase. Multi-threaded CPU-bound work sees ~4x speedup.
  • C extensions must opt in via Py_mod_gil. If they don't, the interpreter re-enables the GIL silently for the whole process.
  • Memory cost: 15-20% higher than the standard build (per-object locks add up).
  • Timeline: Phase 2 in 3.14 (now); Phase 3 (GIL off by default with opt-back-in) likely 2027-2028; full GIL removal in 2029-2030.
Free-threaded Python timeline and benchmark comparison Free-threaded Python: timeline + benchmarks 2023 PROPOSAL · 2025 OFFICIAL · ~2029 DEFAULT ROADMAP 2023 PEP 703 proposed Oct 2024 3.13: experimental ~40% overhead Oct 2025 3.14: PEP 779 OFFICIAL 5-10% overhead today 2027-2028 (est.) GIL off by default flag-controlled ~2030 (est.) GIL fully removed PYTHON 3.14: GIL BUILD vs FREE-THREADED BUILD SINGLE-THREAD WORKLOAD GIL build = 100 (baseline) free-threaded = 105-110 (5-10% slower) MULTI-THREAD CPU-BOUND GIL build = 100 (single-core effective) free-threaded = 400 (~4x speedup) MEMORY USAGE GIL build = 100 (baseline) free-threaded = 115-120 (~15-20% more) Numbers from pyperformance suite and community benchmarks (danilchenko.dev, Edgar Montano, py-free-threading tracker, 2026). KEY INSIGHT Single-threaded code pays 5-10%. Multi-thread CPU-bound work gains 4x. The trade is genuinely good once your C extensions catch up.
Top: roadmap from PEP 703 proposal to GIL-off-by-default. Bottom: benchmarks comparing the GIL build vs the free-threaded build in Python 3.14.

Why the GIL Existed

The Global Interpreter Lock is a single mutex inside CPython that protects every access to Python objects. Its job is to make reference counting (CPython's primary memory-management mechanism) safe in a multi-threaded interpreter. Without it, two threads modifying the same object's refcount could race, leak memory, or crash the interpreter.

The GIL has been there since the early 1990s. It made CPython simple, fast, and correct on single-core machines, which is what computers were when it was added. As multi-core hardware became standard, the GIL turned into the most criticized aspect of Python: threading can't actually use multiple cores for CPU-bound work because only one thread runs Python bytecode at a time. Workarounds (multiprocessing, asyncio, C extension threads) exist, but they all impose their own trade-offs.

What PEP 703 Replaces the GIL With

Sam Gross's PEP 703 (2023) proposes a design for removing the GIL while keeping reference counting correct. The replacement has three parts:
  • Atomic reference counting using hardware-level atomic operations on object refcounts.
  • Per-object locks for mutable objects (lists, dicts, sets) so concurrent mutation is safe.
  • Biased reference counting as an optimization for single-threaded code: each object has an "owner" thread that uses cheaper non-atomic ops in the common case.
The design accepts a single-threaded overhead in exchange for true parallel multi-threaded execution. In Python 3.13's experimental build, that overhead was about 40%, which was widely seen as too high to default. By Python 3.14, optimizations brought it down to 5-10%, and the trajectory continues.

The Timeline: PEP 779 Phases

PEP 779 specifies the path from experimental to default. Four phases:
  • Phase 1 (3.13, October 2024): experimental free-threaded build, opt-in via --disable-gil when compiling from source. About 40% single-thread overhead. Community testing only.
  • Phase 2 (3.14, October 2025): officially supported but still optional. Ships as a separate prebuilt binary tagged 3.14t. Overhead down to 5-10%. We are here.
  • Phase 3 (estimated 2027-2028): GIL off by default, with a runtime flag or environment variable to re-enable it. Requires single-thread overhead near zero and broad ecosystem compatibility.
  • Phase 4 (estimated 2029-2030): GIL fully removed; the regular build is the free-threaded build.
The transition is intentionally slow because the C extension ecosystem (numpy, pandas, lxml, Pillow, every C-backed library) needs to declare itself thread-safe. Until enough libraries do, defaulting to no-GIL would break too much.PEP 703 Free-Threaded Python: What It Means and When It Lands - 1

Performance: What the Benchmarks Show

Numbers from Python 3.14 (mid-2026):
WorkloadRegular build (GIL)Free-threaded (3.14t)Verdict
Single-thread pyperformance suite100% (baseline)105-110%5-10% slower
Multi-thread CPU-bound (4 threads)100% (single-thread effective)~400%~4x speedup
Multi-thread CPU-bound (16 threads)100%10-14xscales nearly linearly
Multi-thread I/O-bound~100% (GIL released during I/O anyway)~100%no difference
Memory footprint100% (baseline)115-120%15-20% more
The win is concentrated in multi-threaded CPU-bound work, which was previously impossible to parallelize without multiprocessing. The cost is concentrated in single-thread overhead and memory; both are tolerable for the right workload.

For workloads that don't benefit (I/O-bound, single-thread), the regular GIL build is still the right answer in 2026.

Installing the Free-Threaded Build

Several tools support installing both builds side by side.

Via uv (recommended)

# Install free-threaded 3.14
uv python install 3.14t

# Create a project that uses it
uv init --python 3.14t my-project
cd my-project
uv run python -VV
# Python 3.14.x free-threading build (...)

Via pyenv

pyenv install 3.14.0t   # the t suffix for free-threaded
pyenv shell 3.14.0t
python -VV

Via official installers

The python.org Windows and macOS installers offer a checkbox for the free-threaded build during installation. On Linux, distributions ship python3.14 and python3.14t as separate packages.

Both builds can coexist on the same machine. The binary names differ (python3.14 vs python3.14t), and each has its own site-packages, so wheel installations are isolated.

C Extension Compatibility

The biggest practical constraint in 2026: many C extensions haven't yet declared themselves thread-safe. A C extension declares its readiness via the Py_mod_gil module slot.
# In a C extension's PyInit_module:
static PyModuleDef_Slot module_slots[] = {
    {Py_mod_gil, Py_MOD_GIL_NOT_USED},     // I am thread-safe
    {0, NULL}
};
If you import a C extension that doesn't have this declaration, the free-threaded interpreter silently re-enables the GIL for the entire process. Your code still runs, but you've lost the parallelism benefit.

The community tracker at py-free-threading.github.io lists library compatibility status. As of mid-2026:
  • Compatible: numpy, scipy, pandas (recent versions), lxml, Pillow, PyTorch, cryptography, psutil, many others.
  • Partial or in-progress: some database drivers, some niche scientific libraries.
  • Not yet ready: older or unmaintained C extensions, some closed-source vendor libraries.
Before deploying free-threaded in production, check every C extension in your stack. The verification is one-off but mandatory.
Silent fallback warning: the free-threaded interpreter doesn't refuse to import incompatible extensions; it re-enables the GIL silently. Watch the import logs (PYTHONDEVMODE=1 or the runtime flag -X gil=0) to confirm the GIL stays off in your real workload.

When to Migrate

Two cases where free-threaded earns its keep in 2026:

1. CPU-bound parallel work that multiprocessing makes painful

If your workload has heavy compute per task but small inputs and outputs, multiprocessing works fine. If your tasks share large data structures, the IPC pickle overhead becomes the bottleneck. Free-threaded sidesteps the pickling by keeping everything in one process. Image processing on large numpy arrays, ML inference batches, and graph algorithms on big graphs all fit.

2. Embedded or library code that wants threads without forking

If you're embedding Python in a larger application (a game engine, a desktop app, a long-running service), spawning processes is awkward. Threads stay in your process. Free-threaded lets you use multiple cores without resorting to multiprocessing.

Cases where free-threaded is NOT the right answer in 2026:
  • I/O-bound work: stick with asyncio or threading on the regular build.
  • Single-threaded scripts: 5-10% slower than the regular build for no benefit.
  • Stacks with unverified C extensions: silent GIL re-enable defeats the purpose.
  • Production where stability matters more than throughput: wait for Phase 3.

Common Pitfalls

1. Assuming multi-thread CPU code "just works"

You still have to think about race conditions, shared state, and locking. Removing the GIL exposes more concurrency, but it doesn't make your code magically thread-safe. Use threading.Lock for shared mutable state.

2. Mixing builds in one project

Wheels built for the regular build don't necessarily work on free-threaded, and vice versa. Each build has its own wheel tags. Use the same tools (uv, poetry, pip) consistently within a project.

3. Not measuring before migrating

The free-threaded build helps only specific workloads. Benchmark with realistic data; don't assume the published 4x number applies to your code.

4. Ignoring memory cost

15-20% more memory adds up on memory-constrained machines. For workloads with millions of objects, the per-object lock overhead becomes a real consideration.

5. Treating the free-threaded build as the final answer

It's a tool for a specific job (CPU-bound parallelism). asyncio is still the right choice for high-concurrency I/O. multiprocessing is still the right choice for process isolation or sandboxing. The concurrency picture covered in the threads vs processes vs asyncio guide still applies; free-threading just changes one quadrant.

Frequently Asked Questions

What is free-threaded Python and how is it different from regular Python?

Free-threaded Python is a CPython build with the Global Interpreter Lock (GIL) removed. In the standard build, the GIL ensures only one thread runs Python bytecode at a time, which prevents true parallelism for CPU-bound work. The free-threaded build replaces the GIL with atomic reference counting and per-object locks, allowing multiple threads to execute Python bytecode in parallel on multi-core CPUs. PEP 703 designed the architecture; PEP 779 made it officially supported in Python 3.14. The build is opt-in: install python3.14t (the t suffix means threaded) alongside the regular python3.14 to use it.

How much slower is single-threaded code on free-threaded Python?

Roughly 5-10% slower as of Python 3.14, depending on platform and workload. This is a significant improvement from Python 3.13's experimental build, which had about 40% single-thread overhead. The slowdown comes from atomic operations on reference counts and per-object locking that replace the GIL's coarse-grained protection. For multi-threaded CPU-bound work, the overhead is more than paid back: free-threaded shows ~4x speedup on typical workloads when scaling across cores. For purely single-threaded code, sticking with the regular GIL build is still faster.

Will my C extensions work with free-threaded Python?

Many do but not all. C extensions must explicitly declare themselves thread-safe via the Py_mod_gil module slot. If you import a C extension that hasn't declared this, the free-threaded interpreter silently re-enables the GIL for the entire process. Your threads keep running but they won't run in parallel anymore. Major libraries are progressively adding declarations: numpy, lxml, Pillow, and many others have updated wheels. The community tracker at py-free-threading.github.io publishes the current state. Test your stack on a staging environment; assume nothing works until the import logs say it does.

When will the GIL be removed by default in Python?

The current roadmap, per PEP 779 and follow-up discussions on discuss.python.org, has three phases. Phase 1 (3.13, October 2024): experimental build, opt-in via source compile. Phase 2 (3.14, October 2025): officially supported but still opt-in via separate wheel. Phase 3 (estimated 2027-2028): GIL-off as default behavior with the GIL still available via runtime flag. Phase 4 (estimated 2029-2030): GIL removed entirely. The exact timing depends on library ecosystem compatibility, single-thread overhead getting close to zero, and the PSF steering council's assessment. No promises beyond Phase 2.

Should I migrate my production code to free-threaded Python now?

Only if you have a clear CPU-bound parallelism need that multiprocessing can't satisfy and your full C-extension stack is verified compatible. The free-threaded build solves a specific problem (CPU-bound parallel work without IPC overhead) at a real cost (single-thread overhead, 15-20% more memory, ecosystem catching up). For I/O-bound work, asyncio or threading on the regular build is still the right answer. For CPU-bound batch jobs, multiprocessing remains a safer choice in 2026 because of broader compatibility. The honest recommendation: test on staging, deploy free-threaded only where benchmarks justify it, wait for Phase 3 before defaulting new projects to it.

The Bottom Line: Optional Today, Default Tomorrow

The GIL is no longer a permanent fixture of Python. PEP 703 designed the architecture; PEP 779 made the no-GIL build officially supported in Python 3.14. Single-thread overhead is now 5-10%, multi-threaded CPU-bound work sees ~4x speedup, memory grows 15-20%. C extension compatibility is the main practical constraint, with major libraries progressively declaring thread safety. The roadmap targets GIL-off as default in 2027-2028 and full removal by 2030. Adopt free-threaded today for CPU-bound parallel workloads where multiprocessing's IPC overhead hurts; wait for Phase 3 for everything else. This entry closes our Modern Python 2026 series; browse the full Modern Python 2026 guide for the rest.

Learn Multi-Threaded Patterns Through Practice

CodeGym's Python track adds free-threaded workflows to the existing concurrency curriculum across 62 levels: parallel CPU-bound batches, shared-state safety with locks, the right way to migrate from multiprocessing to threads. AI validators catch the race-condition pitfalls; AI mentors explain when free-threaded earns its keep versus when asyncio or multiprocessing fits better. First level free; full plan on the pricing page.