knext

Bytecode caching

Persisting V8 bytecode across cold pods with NODE_COMPILE_CACHE.

Scale-to-zero means cold starts. The expensive part of a Next.js cold start is V8 compiling JavaScript from source. knext skips that work on every cold pod after the first by persisting the V8 bytecode cache to a volume.

How it works (Node)

knext runs the standalone server with NODE_COMPILE_CACHE pointing at a directory. On the first start V8 serializes compiled bytecode to that directory; every later cold pod reads it and skips JS parsing/compilation.

The runtime image starts the server like this:

# NODE_COMPILE_CACHE: V8 bytecode cache for faster subsequent cold starts.
CMD ["sh", "-c", "export NODE_COMPILE_CACHE=\"${NODE_COMPILE_CACHE:-.next/compile-cache}\"; exec node server.js"]

The Dockerfile supplies a fallback path; the operator's externally-injected value wins. When spec.cache.enableBytecodeCache: true, the operator injects:

NODE_COMPILE_CACHE=/cache/bytecode/latest

backed by a PVC, so the cache survives pod death and is shared across cold starts.

Persistence is the whole point. A pod-local cache directory would be re-primed on every cold start and save nothing. The cache must live on a PVC (enableBytecodeCache) to pay off across pods.

Node vs Bun

RuntimeBytecode mechanism
Node (default)NODE_COMPILE_CACHE — the start script and runtime image set it; the operator mounts a PVC. This is the supported, shipping path.
Bunknext can run the same standalone server.js under Bun (spec.runtime: bun), but there is no Bun --compile / Bun-bytecode path wired in knext. Bun runs the server; it does not get a knext-managed bytecode cache.

The project's runtime decision keeps Node + NODE_COMPILE_CACHE as the default: a cold-start benchmark found Bun and Node comparable (scheduling-bound), so there's no Bun-binary rewrite.

On this page