Vite vs Webpack vs Turbopack vs Parcel
TL;DR
Four bundlers, four philosophies. Webpack is the incumbent — flexible, plugin-rich, complex. Vite (2020) flipped the dev story: serve native ESM in dev with esbuild pre-bundling, only bundle for production with Rollup. Turbopack (Vercel/Next.js) is a Rust-native successor to Webpack with similar architecture but much faster. Parcel is the zero-config zero-effort option. For a new project today: Vite unless you’re committed to Next.js (Turbopack) or have a heavy Webpack-only plugin ecosystem.
In depth
What did Vite actually change?
The dev-time story. Old Webpack model: bundle everything → start dev server → HMR re-bundles on change. As apps grew, cold starts crept past 60 seconds.
Vite’s insight: modern browsers support native ESM. In dev, serve files individually, let the browser request each module. Pre-bundle node_modules with esbuild (one-time, cached); ship source files unbundled. Cold start drops to under a second even on large apps.
For production, Vite uses Rollup — proven tree shaking, smaller output, mature ecosystem.
Webpack dev: source → bundler → bundle.js → browser
Vite dev: source → server → individual ESM files → browser
Vite prod: source → Rollup → optimized bundleDev/prod use different tools — initially controversial, now seen as the right separation.
When is Webpack still the right choice?
- Existing project with a Webpack config that works. Don’t migrate for the sake of it.
- React Native — Metro is Webpack-derived.
- Plugin you need only exists for Webpack. Most modern plugins port to Vite, but legacy ones may not.
- Module Federation — Webpack’s flagship feature for micro-frontends; Vite has plugins but Webpack’s is most mature.
For everything else, the perf and DX gap is too big to ignore.
What is Turbopack and how does it compare?
Vercel’s Rust-native successor to Webpack — designed by the original Webpack author. Same architectural model (bundle for dev + prod) but written in Rust with aggressive caching for incremental builds.
| Webpack | Turbopack | Vite (dev) | |
|---|---|---|---|
| Language | JS | Rust | JS + esbuild (Go) |
| Dev cold start | seconds → minutes | seconds | < 1 second |
| HMR speed | slow on big apps | fast | very fast |
| Bundles for dev | yes | yes | no — serves ESM |
| Default in | nothing (configure yourself) | Next.js 15+ (next dev --turbo) |
Vite, SvelteKit, Astro, Remix Vite |
| Maturity | very mature | stabilizing (production-ready 2024) | mature |
Turbopack’s bet: bundling-for-dev with enough caching can match unbundled ESM. For Next.js, it’s the default; outside Next.js, Vite is the more popular choice.
What’s Parcel for?
Zero-config. Point Parcel at an entry HTML, it figures out the rest:
npx parcel index.htmlIt auto-detects: TS, JSX, CSS modules, PostCSS, images, fonts. Just works. Great for small projects, demos, prototypes.
Trade-off: less configurability. For complex apps with custom plugin needs, you outgrow Parcel. For “I want to bundle this thing without thinking,” it’s the smallest setup.
How do you choose for a new app?
Decision tree:
Are you using Next.js?
→ Turbopack (the default in Next 15+)
Is this React Native?
→ Metro (no choice)
Is this a demo / prototype / tiny app?
→ Parcel
Is this a normal app / SPA / library?
→ Vite
Do you have existing Webpack config + team familiarity + plugin lock-in?
→ Stay on WebpackFor 90% of new web frontend projects in 2026: Vite. It’s the modern default, with the largest ecosystem of plugins and integrations.
What about Rollup directly?
Rollup is the bundler under Vite’s production mode. As a standalone tool, it’s the right choice for:
- Library authoring — clean output (ESM + CJS), tree-shakeable, easy to publish.
- Server-side bundles — Node-focused outputs.
For app development, you almost always want Vite (which uses Rollup under the hood) rather than Rollup directly.
Vite’s config — minimal example for React + TS.
// vite.config.ts
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import tsconfigPaths from "vite-tsconfig-paths";
export default defineConfig({
plugins: [react(), tsconfigPaths()],
build: {
target: "es2022",
sourcemap: true,
rollupOptions: {
output: {
manualChunks: {
react: ["react", "react-dom"],
},
},
},
},
server: {
port: 3000,
proxy: { "/api": "http://localhost:8000" },
},
});Compare to a typical Webpack config (often 200+ lines with babel-loader, css-loader, MiniCssExtractPlugin, etc.) — Vite ships sensible defaults so config stays small.
HMR — what’s different between them?
| HMR speed | Granularity | |
|---|---|---|
| Webpack | slow on big apps (re-bundle) | module-level |
| Turbopack | fast | module-level, incremental |
| Vite | very fast | module-level, browser-driven (only the changed file re-fetches) |
Vite’s HMR is the gold standard — edit a React component, browser fetches just that file, React Fast Refresh swaps the component without losing state. Sub-100ms cycle in most cases.
Production build differences.
All four produce bundled output for production. Practical differences:
- Webpack: most config knobs, mature
splitChunkstuning, biggest plugin ecosystem. - Vite (Rollup): smaller output by default, cleaner code-split chunks, automatic
modulepreloadlinks emitted. - Turbopack: aggressive caching across builds, good for incremental CI; comparable output size.
- Parcel: good defaults, less tunable.
Bundle size differences between tools are usually < 10% for the same app; the bigger lever is your code (deps, splitting strategy).
Gotchas / edge cases
- Vite dev != Vite prod — dev serves ESM, prod uses Rollup. Bugs that only appear in
vite build(like CSS extraction order, dynamic imports with side effects) are real and require testing the prod build. - Webpack 5 → Vite migration — most plugins have Vite equivalents; Webpack-specific tools (HardSourcePlugin, etc.) are no longer needed in Vite’s dev model.
commonjs()plugin in Vite — needed for CJS-only deps that don’t ship ESM. Most major libs now ship ESM, but the long tail still requires it.- Turbopack feature parity — still catching up; some Webpack plugins/loaders don’t have Turbopack equivalents.
- Vite’s
optimizeDeps— controls which deps get pre-bundled by esbuild. Sometimes needs manual tuning for monorepo packages or for deps that break pre-bundling. - Parcel’s automatic transforms can surprise — you don’t always know what’s running.
What a senior is expected to say 5
- “Vite for new apps — fast dev via native ESM, Rollup for prod. Turbopack if you’re on Next.js. Webpack for existing projects with no pain point, or React Native.”
- “Vite’s split is real: dev serves ESM (esbuild pre-bundling for node_modules); prod uses Rollup. Test both — bugs hide in prod-only behavior.”
- “HMR speed is the everyday DX win — Vite’s per-file fetch is what made the whole industry rethink dev servers.”
- “Bundle size differences between tools are < 10% in practice. The lever that matters is your code — splitting, tree shaking, dep choice.”
- “Module Federation is Webpack-specific (Vite has a plugin); for micro-frontends with that pattern, Webpack still wins.”
Cross-references
- Transformers (esbuild/SWC/Babel) used inside these bundlers: esbuild vs SWC vs Babel
- Bundle splitting strategy: Bundle Analysis and Code Splitting
- Dev server internals: Dev-Server Internals — HMR, Pre-Bundling, Dependency Resolution
Further reading
- Vite docs: https://vitejs.dev/
- Turbopack docs: https://turbo.build/pack
- Webpack docs: https://webpack.js.org/
- Parcel docs: https://parceljs.org/