· 4 min read
The cliff at 100,000
PostgreSQL 19 turns JIT off by default because the planner could price a query more reliably than the LLVM compilation a cost threshold might suddenly add.

PostgreSQL 19 is going to arrive with one switch in a different position. jit, on by default in PostgreSQL 18, is off in 19. The release notes are unusually candid about why: the optimizer-cost rule that decided when LLVM should join a query was unreliable.
The interesting failure is narrower than “JIT is slow.” PostgreSQL can estimate enough about a query to choose among scans, joins, sorts, and aggregates. What it could not estimate reliably was the compilation bill it was about to add. A query could cross one planner-cost boundary and suddenly acquire a compiler before it acquired its rows.
The threshold priced the query#
With JIT enabled, PostgreSQL compares a plan's total estimated cost with jit_above_cost. The default is 100,000. Those are planner units, not milliseconds. The EXPLAIN documentation calls them arbitrary units determined by planner cost parameters; their job is to compare ways of executing a query.
| stay interpreted | 99,999 |
|---|---|
| JIT eligible | 100,001 |
| jit_above_cost (boundary) | 100,000 |
The switch introduces work from another budget. Tomas Vondra's commit message for the new default says PostgreSQL has no reliable estimate for LLVM compilation and optimization cost. A couple of unrelated inserts can raise a plan estimate just enough to turn JIT on, producing the performance cliff the threshold was meant to avoid.
PostgreSQL's own JIT guide makes the fixed cost visible with a deliberately forced example. A small aggregate finishes in 0.365 ms without JIT. Lower the threshold to 10 and the reported execution time becomes 7.416 ms, with 7.104 ms spent in JIT. The example is intentionally absurd, which is useful here: the missing part of the price is sitting in plain sight.
The compiler still earns its place#
The PostgreSQL 19 JIT guide says compilation is primarily useful for long-running, CPU-bound work, often analytical queries. A long scan or aggregate can spend enough time evaluating expressions for compilation to pay back its entrance fee. Short queries usually cannot.
The problem was choosing between those cases automatically with a score that did not contain a dependable price for the choice itself. The commit notes that large deployments had already learned to disable JIT by default, including the hyperscalers known to the PostgreSQL developers. PostgreSQL 19 follows that practice without removing JIT.
Analytical sites can still enable it, and the same cost thresholds decide which queries compile afterward. That moves one useful bit of workload knowledge outside the planner: an operator can say this is a place where compilation is expected to pay instead of asking query cost to imply it.
A gate needs the price of opening it#
A hard threshold works badly when crossing it adds a fixed cost that the score does not measure. Raising the threshold only moves the discontinuity. Better costing could put compilation into the decision properly; cheaper JIT could make a bad choice less expensive. Vondra's commit leaves both routes open for reconsidering the default later.
For now, the PostgreSQL 19 release notes leave jit_above_cost at 100,000. The threshold is still there. The switch above it is the part that moved.