The Python Free-Threading Ecosystem in 2026 — Who's Ready for NoGIL

Python free threading ecosystem in 2026 — PEP 703/779 status, who declares _Py_mod_gil = 0, and what's blocking adoption.

Free-threaded Python is officially supported. The ecosystem is not.

flowchart TB subgraph BStack["b-stack — _Py_mod_gil = 0"] Bengal[Bengal] Chirp[Chirp] Kida[Kida] Patitas[Patitas] Rosettes[Rosettes] Pounce[Pounce] end subgraph Ecosystem["Most ecosystem — GIL"] Flask[Flask] FastAPI[FastAPI] Jinja2[Jinja2] Markdown[markdown] end Python[Python 3.14t] --> BStack Python --> Ecosystem

TL;DR

  • PEP 703 (PEP 779) made free-threading officially supported in Python 3.14t.
  • The b-stack — Bengal, Chirp, Kida, Patitas, Rosettes, Pounce — declares _Py_mod_gil = 0 and runs on free-threaded Python.
  • Most of the ecosystem still depends on the GIL. One import can silently re-enable it.
  • The gap is wider than people think. See Building for a World That Doesn't Exist Yet for the full story.

Where we are in 2026

PEP 703 proposed making the Global Interpreter Lock optional. PEP 779 defined the criteria for moving free-threaded Python from experimental to officially supported. That happened in Python 3.14.

You can run python3.14t or install it via uv python install 3.14t. The runtime is here. The application ecosystem mostly is not.


PEP 703 and PEP 779 — the roadmap

PEP 703 laid out the design: thread-safe memory allocation, immortal objects, atomic reference counting. PEP 779 defined three phases:

Phase Python Status
I (experimental) 3.13 Opt-in via nogil build
II (officially supported) 3.14 Optional but stable (we are here)
III (default) Future Free-threaded becomes default

Who declares _Py_mod_gil = 0

A C or Rust extension can declare that it is safe for free-threading by setting _Py_mod_gil = 0. If it does not, importing it re-enables the GIL for the entire process.

The b-stack

Library Role
Bengal Static site generator
Chirp Web framework
Kida Template engine
Patitas Markdown parser
Rosettes Syntax highlighter
Pounce ASGI server

Pure Python (except Zoomies). Foundation layer — Kida, Patitas, Rosettes — has almost no external dependencies. The stack runs on free-threaded Python without pulling in GIL-requiring extensions.

What's still blocking

  • NumPy, Pillow, lxml — C extensions that can re-enable the GIL when imported
  • Failure mode is silent: RuntimeWarning that many logging configs swallow

The ecosystem gap

The gap is not just "some libraries don't support it yet." It is that you can think you are running free-threaded and then discover one import turned the GIL back on. See Building for a World That Doesn't Exist Yet for the full story.


How to check your stack

import sys
print(sys._is_gil_enabled())  # False — GIL is off

# Import your app's dependencies one by one
import some_library
print(sys._is_gil_enabled())  # If True, that library re-enabled the GIL

Run this before and after each import. If the GIL turns back on, that library is not yet free-threading ready.