Decide deliberately whether your workload belongs on a free-threaded build, and prove the decision by running your test suite on both builds in CI before any rollout.
- A CPU-bound Python workload where the GIL is the measured bottleneck
- A test suite that runs green on your current build
- Python 3.13 or newer to test free-threaded interpreters
Free-threaded CPython removes the global interpreter lock so CPU-bound threads can truly run in parallel. Python 3.13 shipped it as experimental, 3.14 hardened it, and 3.15 — scheduled for October 2026 — adds a dedicated Stable ABI for free-threaded builds, which lets C extensions be built once for multiple free-threaded versions. Free-threading remains an opt-in build; the default interpreter still has the GIL.
You are done with this guide when you have a written decision — adopt, reject, or defer — backed by a dual-build test run rather than a benchmark you found online.
What free-threading actually changes
- Threads that are genuinely CPU-bound can execute in parallel on multiple cores.
- The trade is a per-interpreter single-thread overhead and stricter requirements on C extensions.
- Opting in means running a separate free-threaded interpreter (the
tbuilds), not flipping a flag.
The official free-threading howto describes the build variants, debugging support, and the C-API contract. PEP 779 defines the acceptance phases that govern when the build stops being called experimental — check its current status rather than assuming.
Decide with a workload, not an opinion
Adopt a free-threaded build when all of these hold:
- Profiling shows the GIL is the bottleneck — not IO waits, not algorithmic cost.
- The workload is CPU-parallel: parsing, compression, image work, numeric loops.
- Your critical C extensions publish free-threaded wheels or you can build them.
Defer or reject when any of these hold:
- The workload is IO-bound — async or a thread pool already saturates it.
- A single process is enough — multiprocessing or a native extension already meets the latency budget.
- A required extension has no free-threaded build and no source path to one.
Prove it with a dual-build CI check
Before any rollout, run your deterministic test suite on both interpreters. With uv you can install and pin the two builds side by side — the free-threaded interpreter uses the t suffix (for example uv python install 3.15t) — then run the suite against each:
uv python install 3.15 3.15t
uv run --python 3.15 -- pytest -q
uv run --python 3.15t -- pytest -q
Treat any difference between the two runs as a finding, not noise: free-threaded builds surface thread-safety bugs that the GIL previously hid. A green run on both builds is the minimum evidence for adoption; add one representative CPU-bound benchmark before and after to confirm the parallelism actually pays for the single-thread overhead.
Rollout and rollback
Ship the free-threaded build the way you ship any runtime change: pinned, reversible, and verified through the real entry point. Keep the GIL build in CI, record both results per release, and roll back to the default interpreter if latency or extension compatibility regresses.
Sources
Every primary reference is linked where it is used: the Python 3.15 release notes for the free-threaded Stable ABI and release scope, the free-threading howto for build variants and the C-API contract, PEP 779 for the acceptance phases, and the uv documentation for installing and pinning multiple interpreters.
Verification record
Editorial review against the Python 3.15 release notes, the free-threading howto, PEP 779, and the uv documentation. Verified 2026-09-06.
About the author
Organizational byline for FlyPython guides, verification records, and corrections. Editorial standards and contact details →