Short answer
--jitless disables V8's entire optimizing pipeline—TurboFan and every tier above the Ignition interpreter—meaning flags like --turbo-fan, --trace-opt, --trace-deopt, and --stress-opt become no-ops. Node.js core JavaScript is designed to be correct without TurboFan, so functional behavior should remain identical; the primary divergence is performance, not semantics. The highest risks are native addons that call V8 optimization intrinsics and timing-sensitive code that may misbehave at interpreter speed.
What --jitless actually turns off
With --jitless, V8 never compiles JavaScript to optimized machine code. Execution remains on the interpreter/baseline bytecode path. Consequently:
--turbo-fan / optimization tiers: Effectively disabled; hot functions are never optimized.--trace-opt / --trace-deopt: Produce no output, as no optimization or deoptimization occurs.--stress-opt / --stress-deopt: Ineffective, as there is no optimizer to stress.
Because the exact set of affected flags varies by V8 release, verify your specific Node.js version using these commands:
node --jitless --v8-options | grep -iE 'jitless|turbofan|sparkplug|maglev'
node --v8-options | grep -iE 'turbofan|sparkplug|maglev'
Comparing these outputs reveals exactly which tiers are disabled in your environment.
Effect on Node.js core modules
Core modules such as crypto, zlib, and fs/promises remain functionally correct under jitless mode but may exhibit higher latency because their JS glue code loses TurboFan's inlining and type-specialization. The underlying native C++ implementations (e.g., OpenSSL) are unaffected. It is likely that experimental features, such as certain WebAssembly fast paths, may have JIT-only implementations; these should be flagged for manual review.
Detecting JIT reliance before deploying
- Dual-run your test suite: Run the full suite twice under identical workloads—once normally and once with
NODE_OPTIONS=--jitless. Compare exit codes, output, and exceptions. This is the most reliable check for functional divergence. - Trace optimization: Run locally with
--trace-opt --trace-deopt to identify which functions are optimized. Functions that are optimized in dev but run interpreted in production are candidates for performance regression. - Stress the optimizer: Use
--stress-opt and --stress-deopt locally. Code that survives forced optimization/deoptimization cycles is unlikely to depend on a specific optimization outcome. - Static scan: Search source code and dependencies for V8 intrinsics (e.g.,
%OptimizeFunctionOnNextCall) or --allow-natives-syntax usage, as these assume an optimizing compiler exists. - Audit native addons: Addons invoking V8 compiler APIs may degrade. Rebuild with symbols and verify they do not request optimization, or include them in the dual-run test.
Caveat
Functional tests may miss timing-dependent bugs, such as race conditions that only surface at interpreter speed. For concurrency-sensitive paths, perform load testing under --jitless. To refine this recommendation, providing your Node.js major version would be helpful, as disabled tiers and experimental JIT-only features are version-specific.