Skip to content
Unverified — AI-generated content. Help verify this page

Vite vs Webpack vs Turbopack vs Rspack

Bundlers are the engine room of frontend development — they transform your source code into optimized assets for the browser. The bundler war has intensified with Rust-based newcomers challenging the JavaScript incumbents. This page compares the four most relevant bundlers across every dimension that matters.

Overview

Vite

Vite (French for "quick") is a build tool created by Evan You in 2020. In development, Vite serves source files over native ES modules — the browser makes individual HTTP requests for each module, and Vite transforms them on-demand using esbuild. This eliminates the bundling step during development entirely, making dev server startup nearly instant regardless of project size. For production, Vite uses Rollup (switching to Rolldown in Vite 6+) to bundle optimized output. Vite has become the default build tool for Vue, Svelte, SolidJS, and most new React projects.

Webpack

Webpack is the build tool that defined modern frontend development, created by Tobias Koppers in 2012. It bundles everything — JavaScript, CSS, images, fonts, WASM — into an optimized dependency graph. Webpack's loader and plugin system is the most extensive in the ecosystem, with thousands of community plugins covering every conceivable use case. Webpack 5 introduced module federation (micro-frontends), persistent caching, and improved tree shaking. It powers most existing production applications including Next.js (production builds).

Turbopack

Turbopack is a Rust-based bundler created by Vercel in 2022, led by Tobias Koppers (Webpack's creator). It is designed as Webpack's successor, using incremental computation to avoid redundant work across builds. Turbopack is integrated into Next.js as the development bundler (replacing Webpack in dev mode) and aims to provide Webpack-level features with Rust-level speed. As of 2026, Turbopack is stable for Next.js development but not yet available as a standalone bundler.

Rspack

Rspack is a Rust-based bundler created by ByteDance in 2023. Unlike Turbopack, Rspack is designed as a drop-in Webpack replacement — it implements the Webpack API, supports most Webpack loaders and plugins, and uses rspack.config.js that mirrors webpack.config.js. This makes migration from Webpack straightforward. Rspack is 5-10x faster than Webpack while maintaining API compatibility.

Architecture Comparison

Key Architectural Differences

Vite does not bundle during development. It serves source files as native ES modules, transforming each file individually with esbuild when the browser requests it. This means startup time is O(1) — it does not increase with project size. The tradeoff is that the first page load in dev can be slow (many HTTP requests), and there is a difference between dev (unbundled ESM) and production (bundled Rollup) behavior.

Webpack builds a complete dependency graph, transforms every file through loaders, and produces optimized bundles. This means startup time is O(n) — it scales with project size. However, Webpack's persistent cache (cache: { type: 'filesystem' }) dramatically improves subsequent startups. Production output is highly optimized.

Turbopack uses function-level incremental computation in Rust. Every function's result is cached, and when inputs change, only the affected computations re-run. This gives Rust-level speed with Webpack-level features. It is tightly coupled to Next.js and not yet a general-purpose tool.

Rspack reimplements Webpack's architecture in Rust, replacing JavaScript execution with native code. It supports Webpack's loader and plugin APIs, so existing Webpack configurations work with minimal changes. Built-in support for TypeScript, JSX, and CSS eliminates the need for many loaders.

Feature Matrix

FeatureVite 6Webpack 5TurbopackRspack 1.x
LanguageJS (esbuild/Rollup/Rolldown)JavaScriptRustRust
Dev serverNative ESM (no bundling)Dev server (full bundling)Incremental (partial bundling)Dev server (fast bundling)
Production bundlerRollup / RolldownWebpackNot yet standaloneRspack
HMRNative ESM HMRWebpack HMRTurbo HMRWebpack HMR compatible
TypeScriptesbuild (type-strip, no checking)ts-loader / babelBuilt-inBuilt-in (SWC)
JSXesbuildbabel-loaderBuilt-inBuilt-in (SWC)
CSSNative, PostCSS, CSS Modulescss-loader, style-loader, MiniCSSBuilt-inBuilt-in
CSS-in-JSPlugin-basedLoader-basedBuilt-in (styled-jsx)Loader-based
Code splittingRollup (dynamic import)SplitChunksPluginAutomaticSplitChunksPlugin compatible
Tree shakingRollup (excellent)Good (improved in v5)YesYes
Module federationPlugin (@module-federation/vite)Built-in (v5)Not yetBuilt-in
Asset handlingBuilt-in (import, ?url, ?raw)file-loader, url-loaderBuilt-inBuilt-in
Environment variablesimport.meta.envDefinePluginBuilt-inDefinePlugin compatible
Source mapsBuilt-inBuilt-inBuilt-inBuilt-in
Persistent cacheDependency pre-bundling cacheFilesystem cacheFunction-level cacheFilesystem cache
Plugin ecosystemRollup plugins + Vite pluginsLargest (thousands)Next.js onlyWebpack loaders + Rspack plugins
Config complexityLow (vite.config.ts)High (webpack.config.js)Managed by Next.jsMedium (rspack.config.js)
SSRBuilt-inPlugin-basedNext.js managedPlugin-based
Library modeBuilt-inBuilt-inNoBuilt-in
Multi-pageBuilt-inManual configNext.js pagesManual config

Code Comparison

Configuration

ts
// vite.config.ts
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';

export default defineConfig({
  plugins: [react()],
  resolve: {
    alias: { '@': '/src' },
  },
  server: {
    port: 3000,
    proxy: {
      '/api': 'http://localhost:8080',
    },
  },
  build: {
    target: 'es2022',
    sourcemap: true,
    rollupOptions: {
      output: {
        manualChunks: {
          vendor: ['react', 'react-dom'],
        },
      },
    },
  },
});
js
// webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const TerserPlugin = require('terser-webpack-plugin');

module.exports = {
  entry: './src/index.tsx',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: '[name].[contenthash].js',
    clean: true,
  },
  resolve: {
    extensions: ['.ts', '.tsx', '.js', '.jsx'],
    alias: { '@': path.resolve(__dirname, 'src') },
  },
  module: {
    rules: [
      {
        test: /\.tsx?$/,
        use: 'ts-loader',
        exclude: /node_modules/,
      },
      {
        test: /\.css$/,
        use: [MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader'],
      },
      {
        test: /\.(png|svg|jpg|gif)$/,
        type: 'asset/resource',
      },
    ],
  },
  plugins: [
    new HtmlWebpackPlugin({ template: './index.html' }),
    new MiniCssExtractPlugin({ filename: '[name].[contenthash].css' }),
  ],
  optimization: {
    minimizer: [new TerserPlugin()],
    splitChunks: {
      cacheGroups: {
        vendor: {
          test: /[\\/]node_modules[\\/]/,
          name: 'vendor',
          chunks: 'all',
        },
      },
    },
  },
  devServer: {
    port: 3000,
    proxy: [{ context: ['/api'], target: 'http://localhost:8080' }],
  },
  cache: { type: 'filesystem' },
};
js
// rspack.config.js
const { HtmlRspackPlugin } = require('@rspack/core');

module.exports = {
  entry: './src/index.tsx',
  output: {
    filename: '[name].[contenthash].js',
    clean: true,
  },
  resolve: {
    extensions: ['.ts', '.tsx', '.js', '.jsx'],
    alias: { '@': path.resolve(__dirname, 'src') },
  },
  module: {
    rules: [
      {
        test: /\.tsx?$/,
        use: {
          loader: 'builtin:swc-loader', // Built-in, no npm install needed
          options: {
            jsc: { parser: { syntax: 'typescript', tsx: true } },
          },
        },
      },
      {
        test: /\.css$/,
        type: 'css', // Built-in CSS handling
      },
    ],
  },
  plugins: [new HtmlRspackPlugin({ template: './index.html' })],
  optimization: {
    splitChunks: {
      cacheGroups: {
        vendor: {
          test: /[\\/]node_modules[\\/]/,
          name: 'vendor',
          chunks: 'all',
        },
      },
    },
  },
  devServer: {
    port: 3000,
    proxy: [{ context: ['/api'], target: 'http://localhost:8080' }],
  },
};

Configuration comparison

Vite's config is 25 lines. Webpack's is 60+ lines. Rspack's is in between — it uses Webpack's API but eliminates many loaders with built-in transforms. This is not just cosmetic: simpler config means fewer dependencies, fewer version conflicts, and faster onboarding.

Plugin/Loader Example

ts
// vite-plugin-markdown.ts
import { Plugin } from 'vite';
import { marked } from 'marked';

export function markdown(): Plugin {
  return {
    name: 'vite-plugin-markdown',
    transform(code, id) {
      if (!id.endsWith('.md')) return;
      const html = marked(code);
      return {
        code: `export default ${JSON.stringify(html)}`,
        map: null,
      };
    },
  };
}
js
// markdown-loader.js
const { marked } = require('marked');

module.exports = function (source) {
  const html = marked(source);
  return `export default ${JSON.stringify(html)}`;
};

// webpack.config.js — must also register:
// { test: /\.md$/, use: './markdown-loader.js' }

Performance

Dev Server Startup

Project SizeViteWebpack (cold)Webpack (cached)TurbopackRspack
Small (50 modules)300ms3s800ms200ms400ms
Medium (500 modules)400ms12s2s400ms1.5s
Large (2,000 modules)600ms45s5s800ms3s
Huge (10,000 modules)1.2s120s+15s1.5s8s

Vite's startup secret

Vite's startup time barely increases with project size because it does not bundle during development. The "startup" is just launching an HTTP server. The cost shifts to the first page load, where the browser makes many individual module requests. For most projects, this tradeoff is dramatically better than waiting for a full bundle.

Hot Module Replacement (HMR)

Project SizeViteWebpackTurbopackRspack
Small20ms200ms15ms50ms
Medium30ms500ms20ms80ms
Large50ms1-3s30ms150ms
Huge80ms3-10s50ms300ms

Production Build

Project SizeVite (Rollup)WebpackRspack
Small2s5s1s
Medium8s20s3s
Large25s60s8s
Huge60s180s+20s

Dev vs prod consistency

Vite uses different tools for development (esbuild/native ESM) and production (Rollup). This can cause subtle differences — a feature that works in dev might break in production. Webpack, Rspack, and Turbopack use the same engine for both modes, ensuring consistency. Vite 6+ with Rolldown aims to close this gap.

Bundle Output Size

MetricVite (Rollup)Webpack 5Rspack
Tree shaking qualityExcellentGoodGood
Code splittingGoodExcellent (granular control)Excellent
CSS extractionBuilt-inMiniCssExtractPluginBuilt-in
Asset inliningConfigurable (assetsInlineLimit)url-loader equivalentConfigurable
Minificationesbuild (fast) or terserterser (slower, better)SWC (fast)

Developer Experience

Learning Curve

AspectViteWebpackTurbopackRspack
Time to working project2 min (npm create vite)15-30 min2 min (create-next-app)10-15 min
Config complexityLowHighNone (Next.js manages)Medium (Webpack-like)
Concept countLow (plugins, server, build)High (loaders, plugins, resolve, entry, output, optimization)Very low (managed)Medium (Webpack concepts)
DebuggingEasy (source maps, clear errors)Hard (loader chains, plugin ordering)Easy (managed)Medium
DocumentationExcellentGood (but dense)Minimal (part of Next.js docs)Good

Ecosystem

CategoryViteWebpackTurbopackRspack
Plugin count500+ (plus Rollup plugins)5,000+N/A (Next.js only)Webpack loaders + Rspack plugins
Framework supportReact, Vue, Svelte, Solid, QwikAllNext.js onlyReact, Vue (via Rsbuild)
Meta-frameworkNuxt, SvelteKit, Remix, AstroNext.js (prod)Next.js (dev)Rsbuild (standalone)
CSS frameworksAll (native PostCSS, Tailwind)All (via loaders)AllAll
TestingVitest (native)JestJestJest or Vitest

When to Use Which

Decision Summary

ScenarioBest ChoiceWhy
New project (any framework)ViteFastest DX, simplest config, modern default
Next.js projectTurbopack (dev)Built-in, Vercel-managed, Rust speed
Existing large Webpack projectRspackDrop-in replacement, 5-10x faster
Micro-frontendsWebpack or RspackModule federation support
Library authoringVite (library mode)Simple config, good tree shaking
Enterprise with Webpack infraRspackMinimal migration, huge speed gain
Maximum build speedRspackRust-native, fastest production builds
Maximum ecosystemWebpackMost plugins, most examples
MonorepoVite or RspackGood workspace support, fast

Migration

Webpack to Vite

  1. Install: npm install -D vite @vitejs/plugin-react
  2. Create config: vite.config.ts with framework plugin
  3. Move index.html: From /public/index.html to root, add <script type="module" src="/src/main.tsx">
  4. Replace env vars: process.env.REACT_APP_* becomes import.meta.env.VITE_*
  5. Replace imports: require() becomes import, asset imports use ?url or ?raw
  6. Replace loaders: Most loaders are unnecessary — Vite handles TS, CSS, JSON, assets natively
  7. Update scripts: "dev": "vite", "build": "vite build"
  8. Remove Webpack: Delete webpack.config.js and all Webpack dependencies

CJS to ESM

The biggest migration pain point is converting CommonJS (require, module.exports) to ESM (import, export). Vite requires ESM for source code. This affects not just your code but also how you import certain npm packages that only ship CJS.

Webpack to Rspack

  1. Install: npm install -D @rspack/core @rspack/cli
  2. Rename config: webpack.config.js becomes rspack.config.js
  3. Replace plugins: HtmlWebpackPlugin becomes HtmlRspackPlugin, MiniCssExtractPlugin becomes type: 'css'
  4. Replace loaders: ts-loader/babel-loader becomes builtin:swc-loader
  5. Keep compatible loaders: Most Webpack loaders work unchanged in Rspack
  6. Update scripts: "dev": "rspack serve", "build": "rspack build"
js
// Minimal changes needed:
// Before (webpack.config.js)
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
  module: { rules: [{ test: /\.tsx?$/, use: 'ts-loader' }] },
  plugins: [new HtmlWebpackPlugin({ template: './index.html' })],
};

// After (rspack.config.js)
const { HtmlRspackPlugin } = require('@rspack/core');
module.exports = {
  module: { rules: [{ test: /\.tsx?$/, use: 'builtin:swc-loader' }] },
  plugins: [new HtmlRspackPlugin({ template: './index.html' })],
};

Rspack is the easiest migration

If you have a large Webpack project and want faster builds without rewriting your config, Rspack is the lowest-effort migration path. Most Webpack configs work with 5-10 lines of changes. Migrating to Vite requires a more significant rewrite.

Verdict

Choose Vite for any new project in 2026. It has the fastest development experience, the simplest configuration, and is the default build tool for Vue, Svelte, Solid, Remix, and an increasing number of React projects. Vite's ecosystem is mature, its plugin API is clean, and Vitest provides a testing framework that shares the same config. The only significant tradeoff is the dev/prod behavior gap (being addressed by Rolldown).

Choose Webpack if you have existing Webpack infrastructure, need module federation for micro-frontends, or rely on specific Webpack plugins that do not have Vite equivalents. Webpack is battle-tested and will remain in production for years. However, for new projects, the configuration complexity and slower build times make it hard to recommend over Vite or Rspack.

Choose Turbopack if you are using Next.js. Vercel is investing heavily in Turbopack as Next.js's default development bundler, and it provides a significant speed improvement over Webpack. You do not need to configure or even think about Turbopack — Next.js manages it. For non-Next.js projects, Turbopack is not yet available as a standalone tool.

Choose Rspack if you have a large existing Webpack project and want 5-10x faster builds with minimal migration effort. Rspack is the pragmatic choice for enterprises — you keep your Webpack knowledge, your Webpack loaders, and most of your Webpack config, but everything runs in Rust. ByteDance uses Rspack across thousands of internal projects, proving its production readiness.

Which Would You Choose?

Scenario 1: Your enterprise has a 2,000-module Webpack monolith. Dev server takes 2 minutes to start, HMR takes 5 seconds per change. Developers are frustrated but a full rewrite is not feasible.

Recommendation: Rspack

Rspack is a drop-in Webpack replacement. Rename your config, swap a few loaders for built-in SWC transforms, and get 5-10x faster builds with minimal changes. Your team keeps their Webpack knowledge, existing loaders mostly work, and you avoid the risk of a full migration to Vite.

Scenario 2: You are starting a new Vue 3 + TypeScript project. You want the fastest possible development experience with minimal configuration.

Recommendation: Vite

npm create vite@latest gives you a working Vue + TypeScript project in 30 seconds. Vite is the official build tool for Vue (created by the same person, Evan You). Dev server starts in ~300ms regardless of project size, HMR updates in ~20ms, and the Vitest testing framework shares the same config.

Scenario 3: You are building a micro-frontend architecture where independent teams deploy separate frontend applications that compose at runtime. Module Federation is a hard requirement.

Recommendation: Webpack (or Rspack)

Module Federation is a Webpack 5 feature that Rspack also supports. Vite has a community plugin for Module Federation, but the Webpack/Rspack implementation is more mature and battle-tested. For production micro-frontends, stay in the Webpack ecosystem.

Common Misconceptions

  • "Vite is not production-ready" — Vite powers production sites at companies like Shopify (Hydrogen), GitLab, and thousands of others. It is the default build tool for Vue, Svelte, SolidJS, and Remix.
  • "Webpack is dead" — Webpack has millions of weekly downloads and powers most existing production applications, including Next.js production builds. It is mature, not dead.
  • "Turbopack replaces Webpack" — Turbopack is currently only available as Next.js's development bundler. It is not a standalone tool and cannot replace Webpack for non-Next.js projects.
  • "Vite and Webpack produce identical output" — Vite uses Rollup (or Rolldown) for production, which has different tree-shaking behavior, code splitting strategies, and minification than Webpack. Test production builds thoroughly when migrating.

Real Migration Stories

Storybook: Webpack to Vite — Storybook 7+ added Vite as a first-class builder alongside Webpack. Teams reported 2-3x faster Storybook startup and HMR when switching to the Vite builder. The migration required minimal config changes because Storybook abstracts the builder.

ByteDance: Webpack to Rspack at scale — ByteDance migrated thousands of internal Webpack projects to Rspack, achieving 5-10x build speed improvements. Their approach: automated config conversion scripts that handled common patterns, with manual fixes for edge cases. The migration validated Rspack's Webpack API compatibility at massive scale.

Quiz

1. Why does Vite's dev server start instantly regardless of project size?

Vite does not bundle during development. It serves source files as native ES modules, transforming each file on-demand when the browser requests it. The "startup" is just launching an HTTP server, which is O(1) regardless of project size.

2. What is the "dev/prod gap" in Vite, and how is it being addressed?

Vite uses esbuild/native ESM for development but Rollup for production. This can cause subtle differences between dev and prod behavior. Rolldown (a Rust port of Rollup) in Vite 6+ aims to unify the dev and prod pipelines.

3. How does Rspack achieve Webpack API compatibility?

Rspack reimplements Webpack's core architecture (dependency graph, module resolution, chunk splitting) in Rust. It supports most Webpack loaders natively and provides built-in SWC-based transforms for TypeScript and JSX, eliminating the need for babel-loader or ts-loader.

4. What is Webpack Module Federation, and why is it significant?

Module Federation allows multiple independently deployed Webpack builds to share code at runtime. Application A can dynamically load a component from Application B without rebuilding. This enables micro-frontend architectures where teams deploy independently.

5. When would you choose Webpack over Vite for a new project?

When you need Module Federation for micro-frontends, when you depend on specific Webpack plugins with no Vite equivalents, or when your deployment pipeline has hard dependencies on Webpack's output format.

One-Liner Summary

Vite is the modern default with instant dev starts and simple config, Webpack has the largest plugin ecosystem, Turbopack is Next.js-exclusive Rust speed, and Rspack is the painless Webpack-to-Rust migration path.

"What I cannot create, I do not understand." — Richard Feynman