Frontend / Build tools / 01_vite_vs_webpack_vs_turbopack.md

Vite vs Webpack vs Turbopack vs Parcel

Updated 6 min read source
On this page6
  1. TL;DR
  2. In depth
  3. Gotchas / edge cases
  4. What a senior is expected to say
  5. Cross-references
  6. Further reading

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.

text
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.

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:

bash
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.

How do you choose for a new app?

Decision tree:

text
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.

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.

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 splitChunks tuning, biggest plugin ecosystem.
  • Vite (Rollup): smaller output by default, cleaner code-split chunks, automatic modulepreload links 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

Further reading