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.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.
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.![PEP 703 Free-Threaded Python: What It Means and When It Lands - 1]()
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.
Both builds can coexist on the same machine. The binary names differ (
The community tracker at py-free-threading.github.io lists library compatibility status. As of mid-2026:
Cases where free-threaded is NOT the right answer in 2026:
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.
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 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-gilwhen 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.

Performance: What the Benchmarks Show
Numbers from Python 3.14 (mid-2026):| Workload | Regular build (GIL) | Free-threaded (3.14t) | Verdict |
|---|---|---|---|
| Single-thread pyperformance suite | 100% (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-14x | scales nearly linearly |
| Multi-thread I/O-bound | ~100% (GIL released during I/O anyway) | ~100% | no difference |
| Memory footprint | 100% (baseline) | 115-120% | 15-20% more |
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 -VVVia official installers
The python.org Windows and macOS installers offer a checkbox for the free-threaded build during installation. On Linux, distributions shippython3.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 thePy_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.
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. Usethreading.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: installpython3.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 thePy_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. |
GO TO FULL VERSION