Karya Semi
HomeBlogSearchCategoriesAboutContact
Karya Semi

Less noise. More notes.

HomeBlogAboutContactPrivacy PolicyDisclaimer

© 2026 Karya Semi. All rights reserved.

XGitHubLinkedIn
  1. Home
  2. /Categories
  3. /Web Development

Vite 8 Migration Guide: Breaking Changes and Upgrade Checklist

A complete step-by-step developer playbook to upgrade your project to Vite 8, handle the Rolldown/Oxc transition, and fix breaking changes.

Dian Rijal Asyrof/August 8, 2026/7 min read
Illustration for Vite 8 Migration Guide: Breaking Changes and Upgrade Checklist

Upgrading a major version of your build tool is rarely just about editing package.json and running npm update. For simple applications, it might work on the first try. But once your codebase grows to include custom configuration, legacy plugins, decorator syntax, or specific CommonJS dependencies, a major upgrade can become a frustrating puzzle of build errors and runtime issues.

Vite 8 is a major shift in how the bundler operates underneath. While our previous look at Vite 8's architecture focused on the move to a unified Rust-powered toolchain, this guide is a hands-on playbook for the developers responsible for doing the actual upgrade.

Here is how to take an existing Vite project, migrate it to Vite 8, resolve configuration changes, and ensure your build remains stable.

Pre-Migration Audit

Before touching your dependency file, prepare your local environment. This prevents you from chasing ghost bugs caused by cached files or mismatched runtimes.

  1. Verify Node.js Version: Vite 8 requires Node.js 20.19+ or 22.12+. Check your runtime with node -v. If your local machine or CI/CD pipelines run on older LTS versions, you must upgrade your environment first.
  2. Commit or Stash Current Work: Never run a major upgrade on a dirty Git tree. Make sure your workspace is clean so you can easily diff the changes or discard them if a blocker appears.
  3. Save a Build Benchmark: Run your production build on the old Vite version and record the build time, bundle size, and chunk count. You will need these numbers later to verify that the migration actually improved your performance.

The Core Engine Shift

Vite 8 moves away from its dual-engine model. In Vite 7 and earlier, the system relied on two separate bundlers: esbuild for pre-bundling dependencies in development, and Rollup for bundling your application in production.

Vite 8 replaces both with Rolldown, a Rust-based port of Rollup. It also swaps out esbuild's parser and transformer with Oxc.

This change simplifies configuration because the development and production pathways now use the same underlying bundler. However, because Rolldown and Oxc interpret configuration options and syntax rules differently than esbuild and Rollup, you will need to adjust your setup.

Configuration Mappings

Vite 8 deprecates several configuration properties in vite.config.ts. The system includes a compatibility layer that automatically maps older properties to their new names, allowing existing configurations to continue working without immediate rewrites, but you should update them manually to avoid deprecation warnings.

Rollup Options Renamed to Rolldown

Because Rollup is no longer under the hood, all configuration options pointing to it have been renamed to target Rolldown. However, the compatibility layer allows existing Rollup configuration keys to continue working seamlessly in Vite 8. You do not need to rewrite your entire config just to complete the basic upgrade.

  • Rename build.rollupOptions to build.rolldownOptions
  • Rename worker.rollupOptions to worker.rolldownOptions

Legacy configurations like build.commonjsOptions and build.dynamicImportVarsOptions.warnOnError are now completely obsolete and act as no-ops. You can safely delete them.

Deprecating esbuildOptions

Since esbuild is no longer the default dependency optimizer, the optimizeDeps.esbuildOptions block is deprecated. Use optimizeDeps.rolldownOptions instead.

The compatibility layer translates these values, but you can use the following mapping reference to update your config file:

Old Config Option (esbuildOptions)New Config Option (rolldownOptions)
minifyoutput.minify
treeShakingtreeshake
definetransform.define
loadermoduleTypes
preserveSymlinks!resolve.symlinks (negated boolean)
resolveExtensionsresolve.extensions
mainFieldsresolve.mainFields
conditionsresolve.conditionNames
keepNamesoutput.keepNames
platformplatform

If you need to inspect the exact configuration generated by the compatibility layer, you can use Vite's configResolved hook inside a custom inline plugin to print the result:

// vite.config.ts
import { defineConfig } from 'vite'
 
export default defineConfig({
  plugins: [
    {
      name: 'log-resolved-config',
      configResolved(config) {
        console.log('Rolldown Options:', config.optimizeDeps.rolldownOptions)
      }
    }
  ]
})

Migrating the esbuild Block to Oxc

JavaScript transformations are now managed by Oxc. The esbuild configuration property is deprecated in favor of oxc. Update your configuration parameters according to this table:

Old Option (esbuild.*)New Option (oxc.*)Notes / Value
esbuild.jsxInjectoxc.jsxInjectInject helper code
esbuild.includeoxc.includeFiles to transform
esbuild.excludeoxc.excludeFiles to skip
esbuild.jsxoxc.jsxOptions like 'preserve'
esbuild.jsxImportSourceoxc.jsx.importSourcecustom JSX package
esbuild.jsxFactoryoxc.jsx.pragmacustom factory function
esbuild.jsxFragmentoxc.jsx.pragmaFragcustom fragment function
esbuild.jsxDevoxc.jsx.developmentdevelopment flags
esbuild.jsxSideEffectsoxc.jsx.purepure annotations
esbuild.defineoxc.defineglobal constants

If your config files used esbuild.jsx: 'automatic' or esbuild.jsx: 'transform', change them to object notation under oxc:

// For automatic JSX
oxc: {
  jsx: { runtime: 'automatic' }
}
 
// For classic JSX transform
oxc: {
  jsx: { runtime: 'classic' }
}

The option esbuild.supported is not supported by Oxc. If your build relies on specific syntax targets, you will need to handle syntax support using alternative Oxc target configurations.

Handling the Native Decorators Gap

Oxc does not yet support lowering native ECMAScript decorators (the 2023-11 spec). If your codebase uses native decorators (common in some Angular, MobX, or server-side TypeScript projects), you cannot rely on Oxc for transformation out of the box.

You can work around this by using SWC or Babel to transform files containing decorators before they reach Oxc.

Workaround 1: Using Babel

Install the Babel plugin and decorator proposals:

pnpm add -D @rolldown/plugin-babel @babel/plugin-proposal-decorators

Configure vite.config.ts to run Babel only on files containing decorator syntax:

import { defineConfig } from 'vite'
import babel from '@rolldown/plugin-babel'
 
function decoratorPreset(options: Record<string, unknown>) {
  return {
    preset: () => ({
      plugins: [['@babel/plugin-proposal-decorators', options]],
    }),
    rolldown: {
      // Run the Babel transform only if the file uses a decorator
      filter: {
        code: '@',
      },
    },
  }
}
 
export default defineConfig({
  plugins: [
    babel({ 
      presets: [decoratorPreset({ version: '2023-11' })] 
    })
  ],
})

Workaround 2: Using SWC

If you prefer SWC for faster execution, install SWC and the rollup helper:

pnpm add -D @rollup/plugin-swc @swc/core

Integrate SWC into your Vite configuration with a code filter:

import { defineConfig, withFilter } from 'vite'
import swc from '@rollup/plugin-swc'
 
export default defineConfig({
  plugins: [
    withFilter(
      swc({
        swc: {
          jsc: {
            parser: { 
              syntax: 'typescript',
              decorators: true, 
              decoratorsBeforeExport: true 
            },
            transform: { 
              decoratorVersion: '2023-11' 
            },
          },
        },
      }),
      // Only transform files with decorator code
      { transform: { code: '@' } }
    ),
  ],
})

Minification Changes

Vite 8 shifts its default minification engines for both JavaScript and CSS.

JavaScript Minification with Oxc

Vite now defaults to the Oxc Minifier instead of esbuild. Because Oxc is written in Rust, it yields faster build times, but its compression logic differs slightly from esbuild.

To configure minifier behaviors like dropping consoles, use build.rolldownOptions instead of the old esbuild.drop settings:

// vite.config.ts
export default defineConfig({
  build: {
    rolldownOptions: {
      output: {
        minify: {
          compress: {
            // Drop console logs in production
            drop_console: true
          }
        }
      }
    }
  }
})

Oxc does not support property mangling options (mangleProps, reserveProps, mangleQuoted, or mangleCache). If your application depends on renaming object keys for safety or compression, you must keep esbuild.

To fall back to esbuild for minification, you must install esbuild as a devDependency (since Vite no longer embeds it) and set your config:

// vite.config.ts
export default defineConfig({
  build: {
    minify: 'esbuild'
  }
})

CSS Minification with Lightning CSS

Lightning CSS is now the default CSS minifier in Vite 8. It handles modern CSS syntax, nesting, and vendor prefixes faster than previous tools.

If Lightning CSS breaks your stylesheets or you need to match a legacy environment, you can switch back to esbuild:

// vite.config.ts
export default defineConfig({
  build: {
    cssMinify: 'esbuild'
  }
})

(Note: Switching back requires adding esbuild to your project's devDependencies).

CommonJS Interop and Resolver Adjustments

Vite 8 introduces stricter guidelines for module resolution. This is where older projects are most likely to experience build errors.

Strict CJS/ESM Interop

Vite 8 uses Rolldown's rules to resolve default imports from CommonJS modules. If a CJS module does not explicitly set __esModule: true, or if the importing file is considered an ES module (by ending in .mjs/.mts or having "type": "module" in package.json), Vite resolves the default import to module.exports instead of trying to look for a nested default property.

If a third-party package fails to import after upgrading, you may see errors like Cannot read properties of undefined or is not a function.

As a temporary fallback while library maintainers update their packages, you can enable legacy interop in your config:

// vite.config.ts
export default defineConfig({
  legacy: {
    inconsistentCjsInterop: true
  }
})

Format Sniffing Removal

In Vite 7, if a dependency package file declared both a browser and module field in its package.json, Vite would read the file content to guess whether to load the ESM file or the browser file.

Vite 8 removes this sniffing heuristic. It strictly honors the field ordering defined in your resolve.mainFields option. If a package resolution breaks because of this change, map the correct entry point manually using resolve.alias:

// vite.config.ts
export default defineConfig({
  resolve: {
    alias: {
      'broken-library': 'broken-library/dist/esm/index.js'
    }
  }
})

Step-by-Step Migration Checklist

Follow these steps to upgrade your repository:

1. Prepare and Update Dependencies

Before running the upgrade, make sure you commit your existing package lockfile so you can track precise dependency changes.

Update Vite along with Lightning CSS for modern CSS builds:

# Using pnpm
pnpm add -D vite@latest lightningcss

If your build relies on legacy plugins that call the transformWithEsbuild utility function, you must add esbuild as an explicit development dependency:

pnpm add -D esbuild

You do not need to delete your package lockfile or node_modules directory as a standard step. Only clear node_modules or local build caches (like .vite) if you encounter stale dependency states or caching problems during troubleshooting.

2. Update the Configuration File

Open vite.config.ts and apply the configuration updates:

  • Replace any instances of rollupOptions with rolldownOptions.
  • Replace esbuildOptions with rolldownOptions options using the mapping table.
  • Replace the esbuild object settings with oxc.
  • Remove obsolete parameters like commonjsOptions.

3. Run the Dev Server

Start your application in development mode:

pnpm exec vite

Open your web browser console and check for errors or deprecation warnings. If you notice dependency resolution errors, check your node_modules structure or enable legacy.inconsistentCjsInterop.

4. Build and Verify

Run the production build:

pnpm exec vite build

Verify that the build exits successfully. Compare the generated files against the build baseline you saved before upgrading.

Post-Upgrade Verification

Before pushing your changes to main, run three validation checks:

  • Compare Bundle Size: Rolldown's chunk generation and Oxc's minifier may compile bundles differently than Rollup and esbuild. Confirm that your output chunk sizes did not grow unexpectedly.
  • Test in Older Browsers: Vite 8 targets Baseline Widely Available browser versions released around mid-2023 (Chrome 111, Firefox 114, Safari 16.4). If your application supports older browser engines, run your test suite against those targets or configure @vitejs/plugin-legacy.
  • Inspect Source Maps: Ensure debugging paths remain valid. Run your build with source maps enabled and verify that stack traces resolve correctly to your source files in your monitoring tools.
DR

Dian Rijal Asyrof

Writes about useful AI tools, programming practice, and the craft of building reliable software.

Previous articleBuilding textlog, a Quiet and JavaScript-Free Microblogging Platform
ViteFrontendBuild ToolsWeb Development
On this page↓
  1. Pre-Migration Audit
  2. The Core Engine Shift
  3. Configuration Mappings
  4. Rollup Options Renamed to Rolldown
  5. Deprecating esbuildOptions
  6. Migrating the esbuild Block to Oxc
  7. Handling the Native Decorators Gap
  8. Workaround 1: Using Babel
  9. Workaround 2: Using SWC
  10. Minification Changes
  11. JavaScript Minification with Oxc
  12. CSS Minification with Lightning CSS
  13. CommonJS Interop and Resolver Adjustments
  14. Strict CJS/ESM Interop
  15. Format Sniffing Removal
  16. Step-by-Step Migration Checklist
  17. 1. Prepare and Update Dependencies
  18. 2. Update the Configuration File
  19. 3. Run the Dev Server
  20. 4. Build and Verify
  21. Post-Upgrade Verification

On this page

  1. Pre-Migration Audit
  2. The Core Engine Shift
  3. Configuration Mappings
  4. Rollup Options Renamed to Rolldown
  5. Deprecating esbuildOptions
  6. Migrating the esbuild Block to Oxc
  7. Handling the Native Decorators Gap
  8. Workaround 1: Using Babel
  9. Workaround 2: Using SWC
  10. Minification Changes
  11. JavaScript Minification with Oxc
  12. CSS Minification with Lightning CSS
  13. CommonJS Interop and Resolver Adjustments
  14. Strict CJS/ESM Interop
  15. Format Sniffing Removal
  16. Step-by-Step Migration Checklist
  17. 1. Prepare and Update Dependencies
  18. 2. Update the Configuration File
  19. 3. Run the Dev Server
  20. 4. Build and Verify
  21. Post-Upgrade Verification

See also

Illustration for Vite 8 Moves to Rolldown: What Frontend Teams Should Check First
Web Development/Jun 28, 2026

Vite 8 Moves to Rolldown: What Frontend Teams Should Check First

Vite 8 moves its build pipeline to Rolldown and Oxc. Here is what changed, why frontend teams care, and what to test before upgrading.

2 min read
ViteRolldown
Illustration for Jane Street Built a UI Library in OCaml, Web Developers Should Pay Attention
Web Development/Aug 4, 2026

Jane Street Built a UI Library in OCaml, Web Developers Should Pay Attention

Jane Street just open-sourced Bonsai, their OCaml-based UI library. Sounds irrelevant to web devs? It's actually a signal about where frontend architecture is heading.

5 min read
Web DevelopmentFrontend
Illustration for Frontend Bundle Optimization: Eliminating Dead Code and Side Effects
Web Development/Aug 1, 2026

Frontend Bundle Optimization: Eliminating Dead Code and Side Effects

How to audit dynamic imports, parse dependency graphs, and configure bundlers to prune dead code and side-effect modules for faster page hydration.

6 min read
Web DevelopmentBest Practices