DEV Community

Vite 8 Complete Guide: Rolldown, Oxc, and 10x Faster Builds (2026)

Build times in modern frontend development fell off a cliff in March 2026. Vite 8 shipped with Rolldown - a Rust-based bundler that replaces both esbuild and Rollup, runs the same Vite plugin API, and cuts production build times by 10-30x in real-world projects. Linear's build went from 46 seconds to 6. GitLab's shrank by 7x. This guide covers Vite 8 from initial setup to production optimization: what the new Rust toolchain actually changes, Full Bundle Mode, TypeScript path resolution without plugins, and migrating from Vite 6 or 7.

What Vite Does

Vite solves two different problems with two different strategies.

Development: No bundling. Vite serves files over native ES modules directly to the browser on-demand. Dev server startup is sub-300ms regardless of project size.

Production: Full bundling. Vite produces an optimized bundle - tree-shaken, code-split, minified. Previously this used esbuild for transforms and Rollup for bundling, which meant slightly different behavior between dev and prod. Vite 8 solves that with a single unified Rust toolchain.

What Changed in Vite 8

Vite 8 replaces the dual-tool production pipeline:

  • Rolldown (bundler) replaces Rollup
  • Oxc (parser, transformer, minifier) replaces esbuild
  • Both are Rust-based, from the VoidZero team
  • Single toolchain = identical dev and prod semantics

Installation

# New project
npm create vite@latest my-app -- --template react-ts
cd my-app
npm install
npm run dev

# Existing project
npm install --save-dev vite@latest @vitejs/plugin-react@latest

Vite 8 requires Node.js 20.0.0 or higher.

vite.config.ts Anatomy

import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'

export default defineConfig({
  plugins: [
    react(), // @vitejs/plugin-react v6 - Oxc-based, no Babel
  ],
  resolve: {
    // New in Vite 8: native TypeScript path alias resolution
    tsconfigPaths: true,
  },
  server: {
    port: 3000,
    open: true,
    proxy: {
      '/api': {
        target: 'http://localhost:8080',
        changeOrigin: true,
        rewrite: (path) => path.replace(/^\/api/, ''),
      },
    },
  },
  build: {
    outDir: 'dist',
    sourcemap: true,
    rollupOptions: {
      // Rolldown-compatible - most Rollup options work as-is
      output: {
        manualChunks: {
          vendor: ['react', 'react-dom'],
          router: ['react-router-dom'],
        },
      },
    },
  },
})

The Rust Toolchain: Rolldown + Oxc

Rolldown

Rolldown is not just Rollup rewritten in Rust - it's designed from scratch with Vite's use case in mind:

  • 10-30x faster on real projects
  • Module-level persistent caching - only re-bundles what changed
  • Full Bundle Mode (see below)
  • Module Federation support built-in
  • Better chunk splitting

The existing rollupOptions in your config works. There's a compatibility layer that auto-converts esbuild and Rollup configuration to Rolldown equivalents. For most projects, upgrading requires zero config changes.

Oxc

Oxc is the parser and transformer Rolldown uses internally. In Vite 8 it handles TypeScript stripping, JSX transform, minification, and tree-shaking - all faster than esbuild.

The impact on @vitejs/plugin-react v6:

# Vite 7 - requires Babel
@vitejs/plugin-react โ†’ @babel/core + plugins (~45MB)

# Vite 8 - Oxc-based
@vitejs/plugin-react@6 โ†’ no Babel (~8MB)

If you had custom Babel config in plugin-react, find the Oxc or Vite plugin equivalent:

// Vite 7 - Babel custom plugins
react({
  babel: {
    plugins: ['babel-plugin-styled-components']
  }
})

// Vite 8 - Babel is gone; use Vite plugin equivalents
react()
// For styled-components: use @vitejs/plugin-oxc-styled-components

Full Bundle Mode

New in Vite 8 - bundles during development too:

export default defineConfig({
  dev: {
    bundleMode: true,
  },
})

Results on large projects:

  • 3x faster dev server startup
  • 40% faster full reloads
  • 10x fewer network requests
  • Dev and prod behavior identical

For small projects (under ~100 modules), unbundled mode is still faster. Full Bundle Mode's benefits become significant at medium-to-large scale. HMR continues to work - only the affected module chunk is invalidated.

TypeScript Paths Without Plugins

Previously you needed vite-tsconfig-paths. Vite 8 reads your tsconfig.json natively:

// vite.config.ts
export default defineConfig({
  resolve: {
    tsconfigPaths: true, // reads paths from tsconfig.json
  },
})
// tsconfig.json - these paths now work without any plugin
{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@/*": ["./src/*"],
      "@components/*": ["./src/components/*"],
      "@hooks/*": ["./src/hooks/*"]
    }
  }
}

Uninstall vite-tsconfig-paths - it's no longer needed.

Environment Variables

# .env
VITE_API_URL=https://api.example.com
# Variables without VITE_ prefix are NOT exposed to the browser
// In your code
const apiUrl = import.meta.env.VITE_API_URL
const isDev = import.meta.env.DEV // boolean
const isProd = import.meta.env.PROD // boolean

TypeScript types for env variables (vite-env.d.ts):

/// <reference types="vite/client" />

interface ImportMetaEnv {
  readonly VITE_API_URL: string
  readonly VITE_APP_NAME: string
}

interface ImportMeta {
  readonly env: ImportMetaEnv
}

Build Optimization

Code Splitting

build: {
  rollupOptions: {
    output: {
      manualChunks(id) {
        if (id.includes('node_modules')) {
          if (id.includes('react')) return 'react-vendor'
          if (id.includes('@tanstack')) return 'tanstack-vendor'
          if (id.includes('recharts') || id.includes('d3')) return 'chart-vendor'
          return 'vendor'
        }
      },
    },
  },
},

Bundle Analysis

npm install --save-dev rollup-plugin-visualizer
import { visualizer } from 'rollup-plugin-visualizer'

export default defineConfig({
  plugins: [
    react(),
    visualizer({
      open: true,
      gzipSize: true,
    }),
  ],
})

Run npm run build - opens an interactive treemap of your bundle.

Library Mode

Building a package for npm:

import { resolve } from 'path'
import { defineConfig } from 'vite'
import dts from 'vite-plugin-dts'

export default defineConfig({
  plugins: [dts({ include: ['src'] })],
  build: {
    lib: {
      entry: resolve(__dirname, 'src/index.ts'),
      name: 'MyLib',
      formats: ['es', 'cjs'],
      fileName: (format) => `my-lib.${format}.js`,
    },
    rollupOptions: {
      external: ['react', 'react-dom'],
    },
  },
})

package.json exports:

{
  "main": "./dist/my-lib.cjs.js",
  "module": "./dist/my-lib.es.js",
  "exports": {
    ".": {
      "import": "./dist/my-lib.es.js",
      "require": "./dist/my-lib.cjs.js"
    }
  },
  "types": "./dist/index.d.ts"
}

Migration from Vite 6 or 7

For the majority of projects:

npm install vite@latest @vitejs/plugin-react@latest
npm run build

That's it. The Rolldown compatibility layer handles the rest. If your build passes, you're done.

What to check manually:

// 1. Remove vite-tsconfig-paths
// Before:
import tsconfigPaths from 'vite-tsconfig-paths'
plugins: [react(), tsconfigPaths()]

// After:
resolve: { tsconfigPaths: true }

// 2. Remove Babel config from plugin-react (if any)
// Before:
react({ babel: { plugins: ['babel-plugin-X'] } })
// After: find the Oxc/Vite equivalent

// 3. Node.js version - Vite 8 requires Node.js 20+
// Update CI/CD if using Node.js 18

// 4. Check custom plugins using Rollup-only APIs
// Run npm run build and check for deprecation warnings

With Vitest

Vite 8 and Vitest share the same config file:

/// <reference types="vitest" />
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'

export default defineConfig({
  plugins: [react()],
  resolve: { tsconfigPaths: true },
  test: {
    environment: 'jsdom',
    setupFiles: ['./src/test/setup.ts'],
    globals: true,
    coverage: {
      provider: 'v8',
      reporter: ['text', 'html'],
    },
  },
})

Quick Reference

# Create project
npm create vite@latest my-app -- --template react-ts

# Dev server
vite              # start
vite --port 4000  # custom port
vite --host       # expose to network

# Build
vite build        # production build
vite preview      # preview prod build locally
// Minimal vite.config.ts (Vite 8)
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'

export default defineConfig({
  plugins: [react()],
  resolve: { tsconfigPaths: true },
  dev: { bundleMode: true }, // enable for large projects
  build: {
    rollupOptions: {
      output: {
        manualChunks: {
          vendor: ['react', 'react-dom'],
        },
      },
    },
  },
})

Why It Matters

The numbers are real: 87% build time reductions aren't marketing. A 46-second build becoming 6 seconds changes how you work - you stop avoiding rebuilds, run more experiments, ship faster. More importantly, the dev/prod parity problem is solved. Years of "works in dev, breaks in prod" bugs traced to esbuild/Rollup differences are gone. One toolchain, one behavior.

Full article at stacknotice.com/blog/vite-complete-guide-2026

Comments

No comments yet. Start the discussion.