Python 3.13 shipped an experimental just-in-time compiler behind the --enable-experimental-jit configure flag. The CPython steering council removed it in the 3.14 development cycle because the maintenance cost outweighed the modest speedups. If your build pipelines or Dockerfiles still pass that flag, they will fail on the next release.
By the end of this article you will be able to:
- Detect whether your current builds rely on the removed flag.
- Replace the JIT with the specializing adaptive interpreter that is now the default.
- Verify performance parity with a minimal benchmark harness.
Detect the flag in your build scripts
Search your repository for the configure option. It appears in configure invocations, pyconfig.h checks, and Docker RUN lines.
# Run this at the root of your project
grep -r "enable-experimental-jit" . \
--include="*.sh" --include="Dockerfile*" --include="*.yml" --include="*.yaml"
The command returns every file that still references the flag. Treat each hit as a required edit.
Update Docker images and CI jobs
A typical Dockerfile that built Python from source looked like this:
# Old Dockerfile snippet
FROM debian:bookworm-slim AS builder
RUN apt-get update && apt-get install -y \
build-essential libssl-dev zlib1g-dev \
libncurses5-dev libsqlite3-dev libreadline-dev \
libffi-dev libbz2-dev
RUN wget https://www.python.org/ftp/python/3.13.0/Python-3.13.0.tgz && \
tar xzf Python-3.13.0.tgz && \
cd Python-3.13.0 && \
./configure --enable-experimental-jit --enable-optimizations && \
make -j$(nproc) && make install
Replace the configure line with the standard optimized build. The specializing adaptive interpreter (PEP 709) is enabled by default and delivers most of the speed the JIT promised.
# New Dockerfile snippet
RUN cd Python-3.13.0 && \
./configure --enable-optimizations --with-lto && \
make -j$(nproc) && make install
--with-lto enables link-time optimization, which often matches or exceeds the old JIT gains for long-running services.
Switch to the official slim images
If you compile Python only to get the JIT, stop. The official python:3.13-slim image already includes the adaptive interpreter and is smaller than a custom build.
# Minimal production image
FROM python:3.13-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["python", "-m", "uvicorn", "app:app", "--host", "0.0.0.0", "--port", "8000"]
This change removes the entire builder stage, cuts image size by roughly 300 MB, and eliminates a moving part in your supply chain.
Benchmark before and after
Write a tiny harness that exercises your hot paths. The example below uses pyperf, the same tool the CPython benchmark suite uses.
# bench_hotpath.py
import pyperf
from myapp import hot_function
runner = pyperf.Runner()
runner.bench_func("hot_function", hot_function)
Run it against the old JIT build and the new slim image:
# On the old image
docker run --rm my-old-python-image python bench_hotpath.py
# On the new image
docker run --rm python:3.13-slim python bench_hotpath.py
Compare the median values. In most workloads the difference is within 5 percent; if you see a regression larger than that, profile with python -m cProfile before assuming the JIT removal is the cause.
Where the JIT actually helped
The copy-and-patch JIT benefited tight loops with heavy integer arithmetic and few function calls. The table below summarizes the tradeoffs you can expect when moving to the adaptive interpreter.
If your workload sits in the first row and the regression is unacceptable, the supported path is to drop into a compiled extension (Cython, Rust via PyO3, or plain C) rather than wait for a future JIT.
Key takeaways
- The
--enable-experimental-jitconfigure flag no longer exists in Python 3.14 and will error if used. - The specializing adaptive interpreter is now the default optimization strategy and requires no flags.
- Official
python:3.13-slimimages are smaller, faster to build, and include the adaptive interpreter. - Link-time optimization (
--with-lto) recovers most of the performance the JIT provided for typical services. - For numeric hot loops that regress, invest in typed extensions instead of waiting for another JIT experiment.
Source
Python's experimental JIT to be removed — added detection steps, Docker migration examples, a benchmark harness, and a tradeoff table the original article did not include.
Support this work
These write-ups are researched and published with no paywall, sponsor, or tracking. If one saved you an afternoon, a small tip keeps them coming.
USDT, USDC or USDD · TRC-20 (Tron)
TFTNsfyomKrnUutRjBTGVULp19ByW29KbY
Top comments (0)