Optimizing everything up front would slow startup; interpreting everything would slow busy code. V8 86,723 therefore uses tiers, spending compile time only on functions that prove hot.

The parser builds an abstract syntax tree (AST). Functions that are not called immediately are only pre-parsed, checked for syntax errors and compiled when first called.
Ignition, the interpreter since Chrome 59 1 (2017), compiles the AST to compact bytecode for a register-based interpreter and records feedback: which types and object shapes each operation actually saw.
Sparkplug (Chrome 91, 2021) translates bytecode to machine code in a single pass with no intermediate representation, removing interpreter overhead.
Maglev (Chrome 117, 2023) uses the feedback to emit specialized code guarded by cheap checks; it compiles about 10 times slower than Sparkplug and 10 times faster than TurboFan.
TurboFan, also from Chrome 59, spends the most time for peak speed on the hottest code. Its backend now uses Turboshaft, a control-flow-graph IR that halved compile time.
When a guard fails, V8 deoptimizes: it discards the optimized code, rebuilds the interpreter frame and continues in Ignition. Trace the decisions for tiers.js with node --trace-opt --trace-deopt tiers.js:
function add(a, b) {
return a + b;
}
for (let i = 0; i < 500_000; i++) {
add(i, 1); // feedback: always small integers (Smis)
}
add('tier', 'down'); // a string breaks the assumption[marking add for optimization to MAGLEV, reason: hot and stable] [compiling method add (target MAGLEV)] [completed compiling add (target MAGLEV) - took 0.000, 0.153, 0.001 ms] [bailout (kind: deopt-eager, reason: not a Smi)
The output (Node.js 25.8 2,131 ) is filtered to the lines about add, with addresses removed. The lesson: keep the types flowing through hot functions stable, and profile before micro-optimizing (Memory and Performance).