CPython’s experimental JIT compiler is on its way out of the main branch. The authors of PEP 836, the proposal to turn it into a supported feature, withdrew it on 19 October 2026, and the removal is now planned early in the Python 3.16 development cycle. The story is circulating again this week in Python newsletters, so it is a good moment to answer the practical questions: does this affect your code, how do you check whether your interpreter has the JIT, and how do you measure what it is really worth to you?
What happened, in short
- The copy-and-patch JIT was merged by Brandt Bucher for Python 3.13 as an experimental, off-by-default feature. PEP 744 documented it afterwards as an informational PEP.
- According to LWN’s reporting, in June 2026 the Steering Council paused JIT work on main until a PEP was accepted, with a six-month deadline. PEP 836 (“JIT Go Brrr”) was published on 3 July by Brandt Bucher, Savannah Ostrowski and Ken Jin.
- On 19 October, Savannah Ostrowski posted that the authors were withdrawing the PEP because they “don’t feel we have the personal bandwidth to carry the current version forward”, while still believing in the technical direction. The reference implementation will be published and linked from the withdrawn PEP.
- Also per LWN, the JIT code will be removed from CPython’s main branch early in the 3.16 cycle so that any fallout is found early.
Does this affect you?
For almost everyone, no. The JIT has always been experimental and disabled by default. The speed-ups you already rely on come from other parts of the Faster CPython work, mainly the specializing adaptive interpreter from Python 3.11 (PEP 659). That stays.
The people who should pay attention are:
- Teams who build CPython from source with
--enable-experimental-jitand run it in production. - Anyone who sets
PYTHON_JIT=1in deployment configs or benchmarks. - Distribution packagers and CI maintainers who test JIT builds.
Released versions keep what they shipped. The removal concerns main, which becomes 3.16. Python 3.13, 3.14 and 3.15 continue to receive their normal bugfix and security releases with the JIT code they already contain.
Check whether your interpreter has the JIT
Python 3.14 added a small introspection namespace, sys._jit. The leading underscore marks it as an implementation detail, so guard the lookup:
import os
import sys
jit = getattr(sys, "_jit", None) # only exists on 3.14+
print("Python", sys.version.split()[0])
if jit is None:
print("No sys._jit: this interpreter has no JIT introspection API")
else:
print("JIT compiled in :", jit.is_available())
print("JIT enabled now :", jit.is_enabled())
print("PYTHON_JIT :", os.environ.get("PYTHON_JIT", "<unset>"))
Save it as jitcheck.py and run it twice:
python3 jitcheck.py
PYTHON_JIT=1 python3 jitcheck.py
If is_available() is False, the JIT was never in your build and nothing changes for you. If it is True but is_enabled() stays False until you set the variable, you are on a build that ships the JIT switched off, which is the normal default.
Measure it fairly before you worry
If your team believes the JIT speeds up a service, measure it on your own workload. The setting is read at start-up, so each run must be a fresh process. This script runs the same code with the JIT off and on and compares medians:
import os
import statistics
import subprocess
import sys
BENCH = """
import time
def work(n):
total = 0
for i in range(n):
total += i * i % 7
return total
work(10_000) # warm up
start = time.perf_counter()
work(5_000_000)
print(time.perf_counter() - start)
"""
def run(jit_flag: str, repeats: int = 7) -> list[float]:
env = {**os.environ, "PYTHON_JIT": jit_flag}
times = []
for _ in range(repeats):
out = subprocess.run(
[sys.executable, "-c", BENCH],
env=env, capture_output=True, text=True, check=True,
)
times.append(float(out.stdout))
return times
off = run("0")
on = run("1")
print(f"JIT off: median {statistics.median(off):.3f}s")
print(f"JIT on : median {statistics.median(on):.3f}s")
print(f"ratio : {statistics.median(off) / statistics.median(on):.2f}x")
On an interpreter without the JIT, both medians should match within noise. That is your control: it tells you how big a difference must be before it means anything. A tight numeric loop like this is close to a best case for a JIT, so expect your real application to show a smaller gain. For serious numbers use pyperf or the pyperformance suite, which handle warm-up, CPU pinning and outliers.
Clean up configs that assume a JIT
Search your repositories for leftovers that will become meaningless on 3.16 builds:
grep -rnE "PYTHON_JIT|enable-experimental-jit" \
--include="*.yml" --include="*.yaml" --include="Dockerfile*" \
--include="*.toml" --include="*.cfg" --include="*.sh" .
Typical hits are a PYTHON_JIT=1 line in a Dockerfile, a CI matrix entry that builds CPython with the JIT flag, or a benchmark job comparing JIT on and off. Keep them for 3.13-3.15 if they help you, but don’t carry them into 3.16 test pipelines expecting them to do anything once the code is gone from main.
Where to get speed instead
If you were counting on the JIT for performance, these are the levers that remain:
- Upgrade. Each recent release has shipped interpreter improvements. Python 3.16 alpha 2, for example, lists faster startup and C implementations of
uuid4()anduuid7()in its release notes. - Profile first. Find the hot path with
cProfileor a sampling profiler before changing anything. - Vectorise or move hot loops out of Python with NumPy, Polars, Cython or a Rust extension.
- Use the free-threaded build for CPU-bound work that can run in parallel threads, after testing your dependencies.
Is a JIT gone for good?
Not necessarily. The withdrawal post says the authors still believe in the direction, including free-threading support and a method-based frontend, and the reference implementation will stay public. Any future attempt will need a new PEP that answers the Steering Council’s questions about support commitments, performance, platform parity, user impact and security.
Takeaway
The CPython JIT removal is mostly a governance story, not a performance emergency. Run the two short scripts above: if sys._jit.is_available() is false or the A/B ratio is within noise, you have nothing to change. If you do rely on PYTHON_JIT=1, keep it on 3.13-3.15, remove it from 3.16 plans, and put your optimisation effort into profiling, upgrades and native extensions.
Sources: PEP 836 (Withdrawn), withdrawal announcement on discuss.python.org, PEP 744.
