skip to content

Does CPython 3.14 ship a JIT compiler, and is it enabled by default?

level: juniorimportance: nice to knowfreq 20%

answer

  1. Newer CPython does have one
  2. But you do not get it automatically
  3. Two gates: the build and the launch
  4. An environment variable turns it on
  5. Ask sys whether the build has it

basics

~20 s

CPython carries an experimental machine-code JIT, first added in 3.13, but it is opt-in twice over: the interpreter must be built with it, and the process must be started with PYTHON_JIT=1. Most installed builds have it off or absent.

solid answer

~40 s

CPython gained an experimental copy-and-patch JIT in **3.13**, and in **3.14** it is still experimental and still off by default — it is never the reason a stock interpreter is fast. Two gates sit in front of it: the interpreter has to be *built* with JIT support (a configure-time option), and the process has to be started with the environment variable `PYTHON_JIT=1`. `sys._jit.is_available()` tells you whether the running interpreter has the machinery at all, and on a typical installed 3.14 it answers `False`. Published measurements range from roughly 10% slower to 20% faster depending on the workload, because copy-and-patch emits code quickly but optimizes it very little. The speedup people actually notice when upgrading comes from the adaptive specializing interpreter added in 3.11, which needs no flag.

code

python · 3 lines
python
import sys

print("JIT available in this build:", sys._jit.is_available())

go deeper

for a junior

Be ready to say plainly that CPython's JIT is experimental and opt-in, and that ordinary Python is still an interpreter running bytecode. Knowing the environment variable name and the availability check is more than enough here.

for a middle

Explain the two gates — built with JIT support, then started with PYTHON_JIT=1 — and separate the JIT from the always-on specializing interpreter that actually delivered the 3.11+ gains.

for a senior

Be able to say why you would not enable an experimental optimizer in production without your own before/after measurements, and why an I/O-bound service gains nothing from it.

for a principal

Own the position on when experimental runtime features enter your platform baseline at all: what evidence you would require, how you would roll it back, and why chasing a single-digit interpreter gain rarely beats fixing the actual bottleneck.

## Two different things that made modern Python faster When someone says "Python got faster", two separate mechanisms are usually being blurred together, and the interview value of this question is knowing which is which. The first is the **adaptive specializing interpreter**, shipped in **3.11** under PEP 659. It is on in every ordinary CPython build, needs no flag and emits no machine code: it rewrites hot bytecode into type-specialized forms. That is the mechanism behind most of the version-to-version gains from 3.11 onward. The second is the **JIT**, added as an experimental feature in **3.13** and still experimental in **3.14**. This one really does emit machine code, and it really is off unless you deliberately turn it on. ## How the JIT is gated There are two independent gates. **Build time.** The JIT is a configure-time option; an interpreter compiled without it simply has no code generator inside. Many distribution packages and installers ship without it, so "my Python is 3.14" says nothing about whether a JIT exists in the binary. **Run time.** Even in a build that has it, the JIT stays dormant unless the process starts with the environment variable `PYTHON_JIT=1`. That is deliberate: an experimental optimizer that silently activated in production would be a support nightmare, and the project wants opt-in telemetry from people who chose it. The honest way to answer "do I have it?" is to ask the interpreter rather than to reason about your version number: ```python import sys print(sys._jit.is_available()) ``` The leading underscore is a signal in itself: this is an unstable, internal-facing surface, not an API to build tooling on. ## What copy-and-patch actually does The design goal was a JIT that could be merged into CPython without a hand-written machine-code backend for every platform. In a copy-and-patch design, the build process compiles a library of tiny pre-built machine-code templates — one per low-level operation the interpreter can perform. At run time, the JIT copies the templates for a hot sequence of operations into a fresh buffer and patches in the concrete values (constants, addresses) each one needs. Stitching templates is extremely cheap compared with running a real optimizing compiler, so compilation time is negligible. The cost of that cheapness is quality. The emitted code removes interpreter dispatch overhead — the loop that fetches, decodes and jumps to each instruction — but it does not do the deep register allocation, inlining and escape analysis a mature JIT does. That is exactly why the measured effect spans "a bit slower" to "noticeably faster": on some workloads the compilation and memory cost outweighs the dispatch savings. ## What to say in an interview A good answer is three sentences long: the JIT exists, it is experimental and opt-in at both build and run time, and it is not what made 3.11+ faster. A candidate who says "Python 3.13 is JIT compiled now" has repeated a headline; a candidate who distinguishes the always-on specializing interpreter from the opt-in experimental JIT has actually read something. A useful follow-on point is what the JIT is *not*. It does not remove the GIL — that is the separate free-threaded build. It does not change semantics, so it cannot make a correct program incorrect (that is the promise; bugs in an experimental feature are the reason it is experimental). It does not replace reference counting or the cycle collector. And it is not comparable to an ahead-of-time compiler that produces a standalone binary: the JIT runs inside a normal CPython process, on code the interpreter is already executing. ## Practical guidance If you are curious enough to try it, treat it as a benchmark exercise, not a deployment decision: run your own representative workload on the same build with and without `PYTHON_JIT=1`, several times, and look at the distribution rather than one number. If your service is I/O-bound — waiting on sockets, disks or a database — nothing about a JIT will help, because the interpreter is not the bottleneck. And whatever you measure today is provisional: an experimental feature's numbers change release to release, which is another reason not to build capacity plans on it.

  • If the JIT is off by default, why did Python 3.11 and 3.12 get measurably faster?
    Because of the adaptive specializing interpreter introduced in 3.11 (PEP 659), plus zero-cost exception handling and cheaper frame and call handling. Those are unconditional interpreter improvements: no build option, no environment variable, no source change. The JIT is a separate, later, opt-in experiment that sits on top of that machinery.
  • Would enabling the JIT help a service that spends most of its time waiting on network calls?
    No. A JIT attacks interpreter dispatch overhead in CPU-bound Python code. If the process is blocked on sockets or disk, that overhead is a rounding error, and the extra memory and compilation work can only hurt. Profile first: optimize the interpreter only once you have shown the interpreter is the bottleneck.

saying these in an interview costs you the question

  • Says Python 3.13 or 3.14 is JIT-compiled by default
  • Confuses the JIT with the 3.11 specializing interpreter
  • Claims the JIT removes or replaces the GIL
  • Expects a large across-the-board speedup from enabling it
  • Thinks PYTHON_JIT=1 works on any build regardless of how it was compiled

context