How to use free-threaded Python in a uv project
Python 3.14 is the first release where the free-threaded build ships as officially supported, after PEP 703: Making the Global Interpreter Lock Optional in CPython introduced it experimentally in 3.13 by removing the GIL and PEP 779: Criteria for supported status for free-threaded Python moved it to phase II in 3.14. This how-to switches an existing uv project to that build, with the dependency-compatibility step that will bite you if you skip it.
If you want to see the performance benefit first on a throwaway project, start with Try Free-Threaded Python with uv.
Install the free-threaded interpreter
uv python install 3.14tThe t suffix requests the free-threaded build. uv keeps standard and free-threaded interpreters side by side, so this does not disturb any existing 3.14 install.
Adjust requires-python first
3.14t is a build variant of Python 3.14, not a separate language version. It satisfies constraints like >=3.14 but not >=3.15. Before pinning, confirm that requires-python in pyproject.toml admits 3.14:
[project]
requires-python = ">=3.14"If requires-python is tighter than the language version of the free-threaded build, pinning fails with an error like The requested Python version '3.14t' is incompatible with the project 'requires-python' value of '>=3.15'. Edit pyproject.toml first, then continue.
Pin the free-threaded build
uv python pin 3.14tThis writes 3.14t into .python-version. Every uv run, uv sync, and uv add in this project now uses the free-threaded interpreter.
Rebuild the virtual environment
uv syncuv detects the new pin, removes the old .venv, and recreates it against 3.14t. Confirm the switch worked:
uv run python -c "import sys; print(sys._is_gil_enabled())"The output should be False. sys._is_gil_enabled() was added in 3.13 so a script can report at runtime which build it is running on.
Check dependencies for free-threaded wheels
Most pure-Python packages work unchanged. C extensions need a free-threaded wheel; otherwise uv falls back to building from source, which needs a compiler and can take minutes per package.
Watch uv sync output for lines that start with Building rather than Downloading. Those are source builds triggered by a missing free-threaded wheel:
$ uv sync
Building some-package==1.2.3
For a broader compatibility survey before you commit to the switch, check the Quansight Labs free-threaded compatibility tracker. Popular scientific-Python packages (NumPy, pandas, SciPy, Pillow) ship free-threaded wheels on recent versions, but niche or unmaintained packages often do not.
When a dependency blocks the switch, options include:
- Wait for upstream. File or follow an upstream issue. Coverage has grown quickly across the 3.13 and 3.14 releases.
- Build from source. Acceptable for small pure-C extensions; painful for packages with heavy build toolchains.
- Isolate the dependency. Move the blocking code into a subprocess or service that runs on a GIL-enabled interpreter while the rest of your project stays free-threaded.
Run your tests
uv run pytestFree-threaded Python exposes thread-safety bugs that the GIL previously hid. Shared mutable state across threads now needs explicit locks, atomic primitives, or message passing. To surface these races, run your existing suite in a thread pool with pytest-run-parallel or pytest-freethreaded, which execute each test across many threads at once. pytest-xdist parallelizes across separate processes, so it speeds up the run but cannot expose the in-process data races free-threading introduces.
Roll back if you need to
uv python pin 3.14
uv syncThis restores the standard GIL-enabled interpreter without touching pyproject.toml or the lockfile.
Learn More
- uv: A Complete Guide covers what uv does, how fast it is, the core workflows, and recent releases.
- Try Free-Threaded Python with uv measures the speedup on a throwaway project
- The official Python free-threading HOWTO covers identification, known limitations, and porting guidance
- The Python Free-Threading Guide on validating thread safety walks through running an existing suite under threads to find races
- PEP 703 is the full proposal for making the GIL optional
- Quansight Labs free-threaded compatibility tracker shows which packages ship free-threaded wheels