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.
Interview Q&A
Q: What did Vite actually change?
A: 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 bundle
Dev/prod use different tools — initially controversial, now seen as the right separation.
Q: When is Webpack still the right choice?
A:
- 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.
Q: What is Turbopack and how does it compare?
A: 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.
Q: What’s Parcel for?
A: Zero-config. Point Parcel at an entry HTML, it figures out the rest:
npx parcel index.html
It 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.
Q: How do you choose for a new app?
A: 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 Webpack
For 90% of new web frontend projects in 2026: Vite. It’s the modern default, with the largest ecosystem of plugins and integrations.
Q: What about Rollup directly?
A: 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.
Q: Vite’s config — minimal example for React + TS.
A:
// 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.
Q: HMR — what’s different between them?
A:
| 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.
Q: Production build differences.
A: 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
- “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: 02_esbuild_vs_swc_vs_babel.md
- Bundle splitting strategy: ../15_performance/03_bundle_analysis_and_code_splitting.md
- Dev server internals: 08_dev_server_internals.md
Further reading
- Vite docs: https://vitejs.dev/
- Turbopack docs: https://turbo.build/pack
- Webpack docs: https://webpack.js.org/
- Parcel docs: https://parceljs.org/