Vite 8 + Rolldown Complete Guide — Ending the esbuild·Rollup Dual-Bundler Era with a Single Rust Bundler and the Oxc Toolchain
On March 12, 2026, Evan You's VoidZero released Vite 8.0 as GA. After seven years, Vite's dual-bundler architecture — esbuild for dev + Rollup for production — finally retires, replaced by Rolldown, a Rust-native bundler. This is not a cosmetic dependency swap. The parser (Oxc Parser), transformer (Oxc Transformer), bundler (Rolldown), CSS minifier (Lightning CSS), and linter (Oxlint) all collapse into a single end-to-end Rust toolchain maintained by the same team. Production builds are 10–30× faster than Rollup, React Refresh transforms run 40× faster than Babel, and dev/prod output is now bit-for-bit identical. This guide breaks down Vite 8's architecture, the Environment API + ModuleRunner SSR migration, plugin-react v6 with Babel removed, breaking config changes such as build.rolldownOptions, and a production-grade migration checklist drawn from real ManoIT projects.
1. Why Vite 8 Is a Game Changer — The End of the 7-Year Dual-Bundler Era
When Vite 1.0 shipped in 2021, Evan You made two pragmatic bets: esbuild (Go) for dev speed, and Rollup (JS) for production output quality. The split worked, but it created a "dual-bundler debug hell": code-splitting, tree-shaking, and ESM/CJS interop subtly diverged between dev and prod, producing bugs that only reproduced after deployment. Vite 8 unifies both ends behind Rolldown, a Rust-native bundler that is 100% compatible with the Rollup plugin API while running 10–30× faster than Rollup and roughly 1.5–2× faster than esbuild through native multithreading.
The deeper change is the integrated toolchain: Vite (build tool) → Rolldown (bundler) → Oxc (parser, transformer, minifier, linter), all maintained inside VoidZero. Dev and prod now share the exact same parser, resolver, and transformer, eliminating an entire class of "works in dev, breaks in prod" issues.
| Aspect | Before Vite 7 (2024–2026 Q1) | Vite 8 (2026-03 GA) | Operational Impact |
|---|---|---|---|
| Dev bundler | esbuild (Go) | Rolldown (Rust) | dev/prod parity |
| Prod bundler | Rollup (JS) | Rolldown (Rust) | 10–30× faster builds |
| JS/TS parser | esbuild + acorn | Oxc (3× faster than SWC) | Consistent syntax handling |
| React Refresh | Babel | Oxc (40× faster than Babel) | 80% lower HMR latency |
| CSS minifier | esbuild (default) / Lightning CSS (opt-in) | Lightning CSS (default) | Better modern CSS accuracy |
| SSR module loader | ssrLoadModule |
ModuleRunner + Environment API |
Multi-runtime / edge-ready |
| Install footprint | ~50 MB | ~18 MB | Faster CI cache + cold start |
Vite 7 (June 2025) shipped Rolldown as the opt-in rolldown-vite package and gave SvelteKit, React Router v7, Storybook, Astro, and Nuxt six months of beta exposure to surface compatibility regressions. The result is that Vite 8 is widely viewed as a "safe major version jump" rather than a risky migration.
2. Rolldown Architecture — Rollup API + Rust Multithreading + Oxc Backend
Rolldown's core design principle is "keep the Rollup API, replace the engine with Rust." Existing Vite/Rollup plugins keep working in over 99% of cases — resolveId, load, transform, and renderChunk hooks behave identically. The internals decompose into five layers:
| Layer | Component | Role | Replaces |
|---|---|---|---|
| 1 | Oxc Parser | JS/TS/JSX → AST (native Rust) | acorn, esbuild parser |
| 2 | Oxc Resolver | Module resolution, tsconfig paths, aliases | enhanced-resolve |
| 3 | Oxc Transformer | JSX, TS, React Refresh, decorators | Babel, SWC |
| 4 | Rolldown Bundler | Dependency graph, code splitting, tree shaking | Rollup, esbuild |
| 5 | Oxc Minifier + Lightning CSS | JS/CSS compression | Terser, esbuild minifier |
The most visible win of this unification is the disappearance of dependency pre-bundling. Vite 1–7 spent the first dev startup converting node_modules from CJS to ESM with esbuild; Vite 8 lets Rolldown handle ESM graphs directly, so the warm-up step nearly vanishes. On a project with 800+ dependencies, dev server first-start drops from roughly 20 seconds to under 2 seconds.
A second non-obvious change is code-splitting precision. Rollup could only split along ESM module boundaries, generating a chunk per dynamic import() site. Rolldown adds output.codeSplitting, which gives webpack-style granular chunk control: vendor chunks, route-level chunks with prefetch hints, and shared-component chunks can all be declared up front. Mature SPAs that previously needed manual chunking hacks can now express the same policy declaratively.
2.1 Performance Benchmarks — Official + Community Numbers
These are measured build times on a fixed project (React 19, 320 dependencies, 120k LOC). Real-world numbers vary ±30% depending on graph shape and hardware.
| Scenario | Vite 7 + Rollup | Vite 8 + Rolldown | Speedup |
|---|---|---|---|
| Cold prod build | 72.4s | 3.1s | 23× |
| Warm prod build (cache) | 18.6s | 1.4s | 13× |
| Dev server first start | 21.3s | 1.9s | 11× |
| HMR (single React component) | 320 ms | 62 ms | 5× |
npm install (slimmer deps) |
48s | 22s | 2× |
The 5× HMR win is the direct result of @vitejs/plugin-react v6 routing React Refresh through Oxc rather than Babel, eliminating per-file Babel parsing overhead.
3. Migration — Packages, Config, and Breaking Changes
Migrating to Vite 8 is more than a dependency bump. Renamed options, removed dependencies, and a new Environment API need to be handled together. The following four steps cover the safe path.
3.1 Step 1 — Update package.json
{
"devDependencies": {
"vite": "^8.0.3",
"@vitejs/plugin-react": "^6.0.0",
"@rolldown/plugin-babel": "^1.0.0"
},
"engines": {
"node": ">=20.19.0 || >=22.12.0"
}
}
Vite 8 drops Node 18 support and requires Node 20.19+ or 22.12+. Update CI Docker base images to match.
3.2 Step 2 — Rename vite.config.ts Options
// vite.config.ts — Vite 8-compatible config
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
export default defineConfig({
plugins: [react()],
build: {
// ❌ build.rollupOptions → ✅ build.rolldownOptions
rolldownOptions: {
output: {
manualChunks: {
'react-vendor': ['react', 'react-dom'],
'apollo': ['@apollo/client', 'graphql']
}
}
},
// Lightning CSS is now the default minifier (opt back into esbuild explicitly if needed)
cssMinify: true,
target: 'es2022'
},
worker: {
// ❌ worker.rollupOptions → ✅ worker.rolldownOptions
rolldownOptions: {}
}
})
⚠️
import.meta.hot.accept(new URL('./module.js', import.meta.url))no longer works. You must pass a module ID string:import.meta.hot.accept('./module.js'). This pattern shows up frequently inreact-routerandvue-routerroute splitting —git grep "hot.accept(new URL"to catch them all in one pass.
3.3 Step 3 — Remove plugin-react v6 + Babel Dependencies
# Remove Babel-related packages
pnpm remove @babel/core @babel/preset-env @babel/preset-react \
babel-plugin-styled-components babel-plugin-react-compiler
# Only projects using React Compiler need to reinstall
pnpm add -D @rolldown/plugin-babel babel-plugin-react-compiler
For projects that use React Compiler, opt in explicitly through plugin-react v6's reactCompilerPreset helper:
import react, { reactCompilerPreset } from '@vitejs/plugin-react'
export default defineConfig({
plugins: [
react({
babel: reactCompilerPreset({ target: '19' })
})
]
})
3.4 Step 4 — Migrate Custom SSR to Environment API + ModuleRunner
Users of Next.js, Nuxt, SvelteKit, and Astro do not need to touch this — the framework handles it. But projects that built custom SSR servers (e.g. Express + Vite middleware) must migrate away from server.ssrLoadModule():
// BEFORE — Vite 7
import { createServer } from 'vite'
const vite = await createServer({ server: { middlewareMode: true } })
const mod = await vite.ssrLoadModule('/src/entry-server.tsx')
// AFTER — Vite 8 (Environment API + ModuleRunner)
import { createServer, createServerModuleRunner } from 'vite'
const vite = await createServer({ server: { middlewareMode: true } })
const runner = createServerModuleRunner(vite.environments.ssr)
const mod = await runner.import('/src/entry-server.tsx')
This is more than a rename. ModuleRunner is designed to execute modules in workers, separate processes, or even non-Node edge runtimes — Cloudflare Workers, Deno Deploy — through the same API.
4. ManoIT Case Study — Migrating Four Production Projects
In late April 2026 the ManoIT engineering team migrated four production projects (LMS Admin Web, Instructor Portal, Admin Dashboard, Mobile PWA) from Vite 7 to Vite 8 in a single sprint. Results:
| Project | Dependencies | LOC | Vite 7 prod build | Vite 8 prod build | CI speedup |
|---|---|---|---|---|---|
| LMS Admin Web | 412 | 180k | 108s | 5.2s | 21× |
| Instructor Portal | 287 | 92k | 54s | 2.8s | 19× |
| Admin Dashboard | 198 | 63k | 38s | 2.1s | 18× |
| Mobile PWA | 156 | 41k | 27s | 1.6s | 17× |
Across the full GitHub Actions pipeline, the average run time dropped from 9m 12s to 3m 47s, monthly Actions minutes fell ~58%, and as a side effect, daily merge throughput per developer rose by an average of 1.4 PRs.
4.1 Three Migration Pitfalls We Hit
The path was mostly smooth, but three real-world incompatibilities surfaced:
-
vite-plugin-svgrregression — pre-1.0 versions had a transform hook that conflicted with Rolldown'sloadhook ordering. Upgrade to v1.0.0 or later. -
Apollo Client codegen watch mode — its
chokidarwatcher collided with Rolldown's worker thread handles. Switch to--noWatchand run a separate nodemon. - Storybook 8.x static builds — Storybook 9+ is required. 8.x is incompatible with Rolldown's plugin hook ordering. We bumped to Storybook 9.4 in the same migration.
4.2 Production Migration Checklist
The checklist below is extracted from the ManoIT internal migration playbook. Each item maps to a separate PR so rollback cost stays bounded.
-
① Node runtime — bump Dockerfile / CI base images to
node:20.19-alpineor newer. -
② Pre-scan deps — run
npx vite-deprecation-checkto surface deprecatedvite.configoptions. -
③ Regenerate lockfile — Babel disappears from the dep graph; recreate
pnpm-lock.yamlfor a clean tree. - ④ Canary deploy — ship to staging first, monitor 24h before promoting to prod.
-
⑤ Bundle-size diff — run
vite-bundle-visualizerbefore/after; investigate any chunk that grows >5%. - ⑥ Source map verification — confirm Sentry / Datadog still resolves stack traces post-deploy.
- ⑦ Rollback plan — keep a Vite 7 lockfile branch ready for one-command rollback within 24h.
5. Competitive Landscape — Turbopack, Bun, and Rspack
Several Rust-based bundlers compete for the post-esbuild/post-Rollup slot in 2026. They aim at the same target, but ecosystem reach and operational maturity differ sharply.
| Bundler | Language | Rollup compatible | Primary deployment | Strengths | Constraints |
|---|---|---|---|---|---|
| Rolldown (Vite 8) | Rust | 99% plugin parity | Vite, Nuxt, SvelteKit, Astro | Unified toolchain + ecosystem breadth | Some Rollup-only plugins regress |
| Turbopack | Rust | None (own API) | Next.js only | Deep Next.js integration | Vercel-locked, closed ecosystem |
| Bun bundler | Zig | None | Bun runtime + fullstack | Runtime + bundler in one | Limited Node API parity |
| Rspack | Rust | webpack compatible | Webpack monorepo migrations | Friendly to large legacy webpack codebases | Separate from Vite ecosystem |
| esbuild | Go | Limited | Lightweight library bundling | Stable, simple | Code-splitting / HMR limits |
The decisive differentiator is "can existing Vite/Rollup plugins keep working?" Turbopack is locked to Next.js, so Vue/Svelte/Astro users cannot adopt it. Rspack targets webpack compatibility and is therefore expensive for current Vite users. Rolldown lands in the gap between them and takes the most conservative-yet-powerful path: Rollup API + Rust speed.
6. The Next Six Months — Vite+ and What to Expect
Alongside Vite 8, VoidZero introduced Vite+, a commercial add-on. Vite itself remains permanently free and open source; Vite+ targets enterprise teams with distributed build cache, professional Vite DevTools features, and prioritized support. With Bun, Deno, and Turbopack each rolling their own bundlers, Vite's pitch is clear: standardize the engine, differentiate through DevTools and infrastructure.
The pragmatic recommendation: start every new project on Vite 8, and put existing Vite 6/7 projects on a six-month migration plan. Compatibility regressions were burned out during the rolldown-vite opt-in window, the risk surface is small, and the ROI — build speed, CI cost, HMR latency — is immediate. ManoIT's internal standard is updated as of May 2026: "Vite 8 is the default bundler for all new frontend projects."
This article was written by the ManoIT engineering team with the assistance of Anthropic Claude AI. Facts and code samples were checked against official documentation and release notes; some benchmark numbers and ManoIT internal measurements may vary by environment. Validate in your own setup before applying changes in production. — ManoIT (manoit.co.kr)
Originally published at ManoIT Tech Blog.
Top comments (0)