What Cloudflare's VoidZero Report Says About Oxc, Rolldown, and Vite Build Times

What Cloudflare's VoidZero Report Says About Oxc, Rolldown, and Vite Build Times

pr0h0•
cloudflarevoidzerooxcrolldownvite
AI Usage (78%)

Introduction

Cloudflare published a retrospective on 2026-09-28 titled "Four months of VoidZero at Cloudflare: making the open-source JavaScript toolchain faster for all humans and agents," and it is worth reading for one reason more than any other. The speedup itself — the thing the headline implies — is not the interesting part. The word agents is. Below I'll separate what the report actually states from what it only implies, walk through the Oxc and Rolldown layers it touches, and show how to benchmark a Vite build cold so you can tell whether any of it applies to your project.

Let me put my position up front. The Rust layer under Vite is real work, and pushing parse, transform, minify, and link into Oxc and Rolldown is the biggest structural change to JavaScript builds since esbuild made everyone care about cold starts. But "faster for agents" is a cold-build and CI argument, not an interactive one. It's also the claim teams are most likely to measure badly — on a warm dev server, on a laptop, on a project whose build time is dominated by JavaScript plugins Rust never touches.

What the Cloudflare VoidZero Report Actually Covers

The four-month timeline and which teams did the work

The published item is confirmed: a Cloudflare Blog post dated 2026-09-28, a retrospective on four months of collaboration between Cloudflare and VoidZero, scoped to speeding up the open-source JavaScript toolchain, with the work landing in the Rust tooling layer that increasingly underpins Vite and downstream frameworks. VoidZero builds Vite, Rolldown, and Oxc, so "collaborating with VoidZero" means contributing upstream rather than shipping a private Cloudflare fork. That last part is my inference from who VoidZero is — the summary doesn't say it outright.

What the summary doesn't name: individual engineers, which Cloudflare org owned the work, which repositories took the commits, or a single speedup number. I'm not going to guess at those.

Separating what the post states from what it implies

ClaimStatus
Four months of Cloudflare/VoidZero work on the OSS JS toolchainConfirmed (publisher, title, date)
Work touches the Rust layer under Vite and downstream frameworksConfirmed (summary)
Framing targets "humans and agents" as distinct beneficiariesConfirmed (title)
Specific percentage or millisecond improvementsNot available in what I have — unverified
Which Vite release train ships which piece by defaultUnverified; check release notes
Agent workloads were a design input rather than a framing deviceImplied, not proven

That last row is the one to watch. A title can describe a workload without that workload having driven a single technical decision.

📝

I'm working from the Cloudflare Blog headline, publication date, and summary surfaced through a news feed — not the full post body. Anything below that describes Oxc, Rolldown, or Vite mechanics comes from those projects' own documentation, and I've marked it as such.

The Two Rust Layers Under Vite: Oxc and Rolldown

Oxc as the parser, transformer, and lint core

Oxc is a Rust toolchain: parser, TypeScript/JSX transformer, minifier, and linter (oxlint). The parser exposes an ESTree-compatible AST across a Node-API boundary, and that detail carries weight — a JavaScript caller can consume native parse output while the rest of the pipeline stays JS. Rolldown skips the boundary entirely and consumes Oxc in-process, file by file.

Rolldown as the bundler replacing the Rollup path

Rolldown is a Rust bundler built on Oxc, and it deliberately targets Rollup-compatible semantics, plugin API included. That compatibility goal is the only reason adoption is plausible: Vite's plugin ecosystem is Rollup-shaped, and a bundler that ignored resolveId/load/transform would orphan all of it.

In the Rolldown-backed Vite variant, both production bundling and dependency pre-bundling (optimizeDeps, historically esbuild's job) move onto Rolldown. Two native engines collapse into one. That's the structural change.

What Vite itself still owns after those layers move to Rust

The dev server, module graph, plugin container, HMR, config resolution, and SSR transform pipeline all stay in Vite. They're JavaScript, and they aren't going anywhere soon — the module graph is mutable state shared with plugins, and plugins are JS by contract.

So the accurate mental model isn't "Vite is now Rust." It's "Vite is a JavaScript orchestrator over Rust primitives," and the profile now piles up in the orchestrator.

Why "Faster for Humans and Agents" Is a Different Performance Bar

Cold builds, warm builds, and who pays for each one

LoopWhat dominatesWho notices
Human editingHMR, module graph updates, warm dep cacheThe developer, in milliseconds
Human pre-commitPartial rebuild, typecheckThe developer, occasionally
Agent editing in CIFull cold install + full cold buildThe whole pipeline, in minutes

A human iterating locally gets a warm node_modules/.vite dependency cache and a long-lived server. An agent that writes files, runs a build, reads the output, and writes more files usually gets the opposite: a fresh container, empty caches, and a full bundle every cycle. The same absolute milliseconds buy wildly different amounts of progress in each loop.

Agent-driven edits break the caching assumptions build tools were designed around

Build caches assume incremental, localized change. Agents break that in specific ways:

  • Broad invalidation. A refactor across 40 files changes the shape of the module graph, not one module.
  • No warm server. Many agent harnesses shell out to vite build per iteration instead of talking to a dev server.
  • Regenerated files. Formatters and codegen rewrite files that "didn't change," which busts mtime-keyed caches.
  • Ephemeral filesystems. On a Docker layer or a fresh CI runner, everything under node_modules/.vite starts cold every time, which makes warm performance improvements worth nothing.

So "faster for agents," read honestly, is an argument that cold-start performance is now a first-class product requirement. A slow cold build costs an agent a timeout or a truncated verification loop, and it costs CI wall-clock minutes on every push.

Measuring Vite Build Times Without Fooling Yourself

A minimal reproducible harness and what to record

Reach for hyperfine so you get distributions instead of vibes, and make the prepare step delete the cache you actually care about:

## bench-cold.sh — cold-cache production build, 5 runs
hyperfine \
  --warmup 1 \
  --runs 5 \
  --prepare 'rm -rf node_modules/.vite dist' \
  'pnpm exec vite build'

Output shape (numbers are yours to fill in — I'm not inventing timings):

Benchmark 1: pnpm exec vite build
  Time (mean ± σ):      <cold-ms> ± <σ-ms>     [User: <u-ms>, System: <s-ms>]
  Range (min … max):    <min-ms> … <max-ms>   5 runs

Record next to it: Node version, package manager version, plugin count, source file count, and whether the run happened on your machine or a shared runner. A timing without those isn't a result.

Then attribute the time, because the aggregate hides where your ceiling is. Here's a small script that takes phase timings and tells you how much is even eligible for the Rust layer:

const phases = { resolve: 900, parse: 2400, transform: 3800, pluginHooks: 6100, bundle: 2700, minify: 1500, write: 600 };
const rs = phases.parse + phases.transform + phases.bundle + phases.minify;
const total = Object.values(phases).reduce((a, b) => a + b, 0);
console.log({ total, rsEligible: rs, rsShare: `${(rs / total * 100).toFixed(1)}%`, jsPlugins: `${(phases.pluginHooks / total * 100).toFixed(1)}%` });
{ total: 18000, rsEligible: 10400, rsShare: '57.8%', jsPlugins: '33.9%' }

That's arithmetic on illustrative inputs, not a measurement of your project — but the shape of the conclusion is the point. If plugin hooks are a third of your build, a Rust layer that becomes infinitely fast still caps you at roughly 58%.

Conditions that invalidate a benchmark result

  • Comparing a cold build with rm -rf node_modules/.vite against a warm one.
  • Running on a shared CI runner with noisy neighbors, or with remote build caching (Turborepo, Nx) enabled on one arm only.
  • Changing plugin sets, optimizeDeps.include, or output targets between arms.
  • Laptop thermal throttling across a long run — randomize the order or benchmark on a fixed machine.
  • Reporting a single run instead of a distribution.
  • Comparing against a different Vite major version and blaming the delta on Rolldown.

Where the Oxc and Rolldown Gains Are Real and Where They Are Not

Parse and transform costs that move to native code

Per-file parse, TypeScript stripping, the JSX transform, minification, and linking are CPU-bound, embarrassingly parallel, and free of a per-node JS boundary once the pipeline is native. On a large TypeScript app, that's where the repeatable wins live — and they show up loudest in exactly the case agents create: a full cold build with an empty cache.

The JavaScript plugin layer Rust never touches

The plugin container still calls your hooks in JS. Every transform call crosses the boundary, and the hook receives and returns JS values. Plugins doing heavy AST work in JS — i18n extraction, CSS-in-JS, GraphQL transforms, custom codegen — keep their entire cost.

The practical implication: audit your plugin time first. If plugins dominate, adopting a Rust bundler is a rounding error until you shrink them or push them native.

Trying the Rolldown-Backed Vite Path in Your Own Project

Adopting the Rust-backed Vite path without breaking CI

The documented approach for the opt-in variant is aliasing vite onto the Rolldown-backed package instead of importing it directly, so every existing vite invocation picks it up:

{
  "overrides": {
    "vite": "npm:rolldown-vite@latest"
  }
}

Confirm the exact field for your package manager (pnpm.overrides, Yarn resolutions), and pin a concrete version rather than @latest before you commit. Then run it as a non-blocking CI job for a couple of weeks before it gates merges:

## compat job — allowed to fail while you evaluate
pnpm install --no-frozen-lockfile
pnpm exec vite build

Compatibility checks to run before committing to it

  1. Enumerate the hooks your plugins implement:
grep -rnoE '\b(buildStart|resolveId|load|transform|renderChunk|generateBundle|augmentChunkHash|moduleParsed|buildEnd|closeBundle)\b' \
  vite.config.* src/plugins/ 2>/dev/null | sort -u
  1. Look for plugins that reach into Rollup internals — this.getModuleInfo, this.emitFile, assumptions about output.format, or anything typed against Rollup's PluginContext.
  2. Check native or WASM addons that assume a specific bundler.
  3. Diff optimizeDeps.include/exclude behavior, since pre-bundling is one of the moving pieces.
  4. Diff the produced dist/ against your current output — file names, chunk splitting, and asset hashes are not guaranteed identical.
⚠️

Chunk splitting and asset hashing changes between bundlers can silently break things that reference hashed filenames — service worker precache manifests, CDN purge rules, and inline import.meta.url asset paths. Diff the output directory, don't just check that the build exits 0.

Open Questions the Cloudflare VoidZero Report Leaves Unanswered

  • How much of the measured improvement comes from Oxc, how much from Rolldown, and how much from Vite-level orchestration? One aggregate number hides the split.
  • Does the post carry agent-specific measurements — cold CI builds, agent iteration loops — or is "agents" a framing layer over human-facing numbers?
  • How deep does Rollup plugin-API compatibility actually go for the long tail, versus the popular dozen plugins?
  • What's the sustainability model for a company-backed Rust toolchain the whole ecosystem now leans on? Concentration risk is an engineering concern, not a governance footnote.
  • Which Vite release makes the Rolldown path the default, and what's the migration story for optimizeDeps edge cases?

Conclusion

The Rust layer under Vite is the right investment, and Cloudflare spending four months on Oxc and Rolldown helps the ecosystem more than another internal build system would. But benchmark this on your warm dev server and you'll conclude nothing changed. You'll be right — for that loop.

Measure the cold path instead. Delete node_modules/.vite, run five builds, record the phase attribution. If your plugin hooks are a third of the total, your realistic ceiling is around a 60% improvement no matter how fast Rust gets, and the next win lives in your plugins. If your cold CI build is the bottleneck, this is the most consequential toolchain shift in years, and the early-access job is worth standing up this week.

Further Reading

Share this post

More posts

Comments