Cutting the cost of JavaScript compilation

Vercel Functions recently moved to a Rust-based core to improve startup times. Now the platform is tackling the next bottleneck in the cold-start path: the time spent parsing and compiling JavaScript before any code can execute.

A new experimental bytecode caching layer targets that compilation step directly, producing measurable gains for larger Next.js applications. In testing across three apps with varying bundle sizes, time-to-first-byte (TTFB) improved by 12–27%, while billed execution duration dropped by roughly half.

Why compilation dominates cold starts

When a JavaScript function starts, V8 must first parse the source and turn it into bytecode before execution can begin. That bytecode can then be JIT-compiled into machine code during runtime. The initial parse-and-compile phase is unavoidable on a truly cold start, but it is also an expensive and purely repetitive operation whenever the same code is loaded again.

Bytecode caching eliminates that repetition. The first execution of a function produces a cache of the compiled bytecode; subsequent cold starts load that cache and skip straight to execution. The caching layer is designed to work on Vercel's ephemeral filesystem, which is wiped clean on each cold start, making the standard v8-compile-cache npm package unsuitable for serverless use.

Instead, Vercel built a custom implementation that persists bytecode caches beyond individual cold starts, and can even merge caches produced by different lazy-loaded chunks. A route like /blog that loads on demand later will generate its own cache entry, which is then folded into the shared cache for future invocations. The more traffic a function receives, the more complete its bytecode cache becomes and the faster subsequent cold starts are.

Measured impact

Vercel benchmarked three Next.js applications with different JavaScript payloads, forcing cold starts every 15 minutes and comparing average startup metrics before and after enabling bytecode caching:

  • A 250 kB main page saw average TTFB improve from 873ms to 764ms (-12%), and billed duration from 330ms to 137ms (-58%).
  • A 550 kB main page improved from 1017ms to 869ms TTFB (-15%), with billed duration dropping from 463ms to 214ms (-54%).
  • An 800 kB main page improved from 1548ms to 1130ms TTFB (-27%), with billed duration falling from 866ms to 453ms (-48%).

Larger applications stand to gain the most: compilation cost scales with code size, so removing it has a bigger relative effect on heavier workloads.

Opting in

Bytecode caching is currently experimental and requires Node.js 20, plus a framework that compiles output to CommonJS (Next.js qualifies). Support for ES Modules is planned via the automatic on-disk code caching option available in Node.js 22.

To enable the feature, add the environment variable USE_BYTECODE_CACHING=1 in your project settings and redeploy. Note that the improvement applies only to production deployments. Vercel has been running the feature internally on its own projects for the past month before opening it up.