| | |

Vite 22 ⚡ Oxc — The high-performance parser & transformer

⏱️ Estimated read: 14 min | |

Oxc is not a single tool. It is a collection of Rust-based compiler components—a parser, a transformer, a minifier, and a resolver—that share the same foundation and are designed to work together . In the Vite 8 toolchain, Oxc sits underneath Rolldown. It parses the JavaScript and TypeScript, transforms the JSX and TypeScript syntax, resolves the module imports, and minifies the output. Rolldown orchestrates the bundle; Oxc does the language-level work . The distinction matters because the migration from esbuild to Oxc is not a single setting. It touches the transform pipeline, the minification behavior, the module resolution, and the TypeScript emit semantics.

The performance numbers are the reason for the swap. Oxc’s parser is roughly 3× faster than SWC and 5× faster than Biome, parsing TypeScript’s own typescript.js in about 26ms where SWC takes 84ms and Biome takes 130ms . The transformer is 4× faster than SWC and 40× faster than Babel, while using less memory and shipping a smaller package . These gains compound across the build because the parser and transformer are invoked for every module in the graph. A faster parser is a faster dev server startup, a faster production build, and a faster lint pass when the same foundation powers Oxlint .

Key point: Oxc replaces esbuild as the transform and minification layer in Vite 8. The configuration surface is the oxc option (renamed from esbuild) for transforms, and build.rolldownOptions.output.minify for minifier options. The old build.minify: 'oxc' shorthand enables the minifier with defaults but does not expose the compression options—the full configuration goes through Rolldown’s output options.


Why Oxc replaces esbuild in the toolchain

The unified foundation problem. Before Vite 8, the toolchain used esbuild for development transforms and Rollup for production bundling. Each tool had its own parser, its own resolver, and its own assumptions about JavaScript syntax. A change in one pipeline could produce a different result in the other, and the glue code that kept them aligned was a maintenance burden . Oxc is the single foundation that both Rolldown and the development pipeline share. The parser that Rolldown uses for bundling is the same parser that transforms the TypeScript, and the same parser that Oxlint uses for linting . The consistency is not a configuration option; it is the architecture.

The TypeScript and JSX transform. Oxc’s transformer handles TypeScript syntax stripping, JSX transformation, and syntax lowering to ES2015 . It is designed to match esbuild’s behavior for the common cases, but it makes different assumptions in a few edge cases. The most consequential is the TypeScript enum handling. esbuild inlines numeric enum values and preserves string enum patterns. Oxc aligns more closely with TypeScript’s own emit behavior, which means it does not inline const enum declarations across file boundaries when isolatedModules is enabled . Vite sets isolatedModules: true implicitly because it transforms files individually, so a project that relies on cross-file const enum inlining must switch to a regular enum or a plain object with as const.

The minifier’s different assumptions. Oxc’s minifier is not a drop-in replacement for esbuild’s minifier. The two tools make slightly different assumptions about source code, and the Vite migration guide links to a comparison of those assumptions . The property mangling options that esbuild supported (mangleProps, reserveProps, mangleQuoted, mangleCache) are not supported by Oxc . A project that relied on property mangling must either accept the larger output or report the gap to the Oxc team. The minifier’s compression options are configured through Rolldown’s output options, not through a top-level Vite key. The dropConsole option, for example, is set at build.rolldownOptions.output.minify.compress.drop_console—and the casing matters. The Oxc API uses snake_case, so dropConsole silently does nothing where drop_console works .

The trade-off. Oxc is faster and more consistent, but it is not a perfect drop-in for every esbuild behavior. The migration is a rename for the common case, and a behavioral adjustment for the edge cases. A project that uses standard TypeScript, standard JSX, and standard minification will not notice the difference except in the build time. A project that uses const enum, property mangling, or esbuild-specific transform options must audit those specific features .


a. Configuring the Oxc transformer

The oxc option replaces the esbuild option in vite.config.ts. The old name is auto-converted with a deprecation warning, but the new name is the one that will remain . The transform options cover JSX, TypeScript, and the target syntax level.

// vite.config.ts — the oxc transform configuration
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';

export default defineConfig({
  plugins: [react()],
  // The oxc option replaces the esbuild option.
  // It configures the transform pipeline that runs before bundling.
  oxc: {
    jsx: {
      // The automatic runtime uses the jsx() function from react/jsx-runtime.
      // The classic runtime uses React.createElement.
      runtime: 'automatic',
      // The import source is the package that provides the JSX runtime.
      importSource: 'react',
    },
    // The target syntax level. Oxc lowers the syntax to this level.
    // The default is the browser target from the build configuration.
    target: 'es2020',
  },
});

The oxc option is the replacement for esbuild, but the mapping is not one-to-one for every sub-option. The jsxFactory and jsxFragment options from esbuild map to oxc.jsx.pragma and oxc.jsx.pragmaFrag. The jsx: 'transform' string maps to oxc.jsx: { runtime: 'classic' }, and jsx: 'automatic' maps to oxc.jsx: { runtime: 'automatic' } . The banner and footer options from esbuild have no direct equivalent in Oxc; a custom plugin with a transform hook is the replacement .

The TypeScript configuration must match the Oxc configuration. If the project uses the automatic JSX runtime, tsconfig.json must have "jsx": "react-jsx" and "jsxImportSource": "react". If the project uses the classic runtime, the tsconfig.json must have "jsx": "react" and the jsxFactory option. A mismatch between the two files is the most common cause of JSX-related build failures after migration . The Oxc transform does not read tsconfig.json directly for the JSX runtime; it uses the oxc.jsx configuration. The two must be kept in sync manually.


b. Configuring the Oxc minifier

The minifier configuration is not on the oxc option. It is on the Rolldown output options. The build.minify: 'oxc' shorthand enables the minifier with defaults, but the compression options are only available through build.rolldownOptions.output.minify .

// vite.config.ts — the oxc minifier configuration
import { defineConfig } from 'vite';

export default defineConfig({
  build: {
    // The minify shorthand enables the minifier with defaults.
    // But it does not expose the compression options.
    minify: 'oxc',
    rolldownOptions: {
      output: {
        // The full minifier configuration goes here.
        // This object is passed to the Oxc minifier inside Rolldown.
        minify: {
          compress: {
            // The drop_console option removes console.* calls.
            // The casing is snake_case. dropConsole (camelCase)
            // silently does nothing.
            drop_console: true,
            // Other compression options are passed here.
          },
        },
      },
    },
  },
});

The double configuration is a source of confusion. Setting build.minify: 'oxc' and build.rolldownOptions.output.minify.compress.drop_console: true at the same time is not necessary. The rolldownOptions route alone engages the Oxc minifier and passes the options. The build.minify: 'oxc' route enables the minifier but does not plumb the compression options through . The canonical configuration is the rolldownOptions route, without the shorthand. If the shorthand is used for clarity, the compression options are still only effective through the rolldownOptions object.

The snake_case casing is a specific trap. The Oxc API uses drop_console, not dropConsole. The camelCase version is silently ignored, which means the console calls remain in the output with no error and no warning . The same applies to other compression options: the Oxc API names are the ones that work, and they are documented in the Rolldown CompressOptions type.


Complete Example Session

// ============================================
// PART 1: THE RENAMED TRANSFORM OPTION
// ============================================

// vite.config.ts
import { defineConfig } from 'vite';

export default defineConfig({
  // The esbuild option is renamed to oxc.
  // The old name is auto-converted but deprecated.
  oxc: {
    jsx: {
      runtime: 'automatic',
      importSource: 'react',
    },
  },
});

// ============================================
// PART 2: THE JSX RUNTIME MAPPING
// ============================================

// esbuild configuration (before):
// esbuild: {
//   jsx: 'automatic',
//   jsxImportSource: 'react',
// }

// oxc configuration (after):
// oxc: {
//   jsx: {
//     runtime: 'automatic',
//     importSource: 'react',
//   },
// }

// The mapping is not one-to-one for every option.
// The jsxFactory option maps to oxc.jsx.pragma.
// The jsxFragment option maps to oxc.jsx.pragmaFrag.

// ============================================
// PART 3: THE TSCONFIG SYNC
// ============================================

// tsconfig.json
// {
//   "compilerOptions": {
//     "jsx": "react-jsx",
//     "jsxImportSource": "react"
//   }
// }

// The tsconfig must match the oxc configuration.
// A mismatch causes build failures that are hard to trace.

// ============================================
// PART 4: THE MINIFIER SHORTHAND
// ============================================

// vite.config.ts — the shorthand
export default defineConfig({
  build: {
    // The shorthand enables the Oxc minifier with defaults.
    // It does not expose the compression options.
    minify: 'oxc',
  },
});

// ============================================
// PART 5: THE MINIFIER OPTIONS
// ============================================

// vite.config.ts — the full configuration
export default defineConfig({
  build: {
    rolldownOptions: {
      output: {
        minify: {
          compress: {
            // The snake_case option name is the one that works.
            drop_console: true,
          },
        },
      },
    },
  },
});

// The shorthand is not needed when the rolldownOptions route is used.
// The rolldownOptions route engages the Oxc minifier and passes the options.

// ============================================
// PART 6: THE CONST ENUM EDGE CASE
// ============================================

// tsconfig.json — with isolatedModules
// {
//   "compilerOptions": {
//     "isolatedModules": true
//   }
// }

// Oxc does not inline const enum across file boundaries
// when isolatedModules is enabled.
// The fix is to use a regular enum or a plain object.

// ❌ const enum Status { Active = 1, Inactive = 0 }
// ✅ enum Status { Active = 1, Inactive = 0 }
// ✅ const Status = { Active: 1, Inactive: 0 } as const;

// ============================================
// PART 7: THE PROPERTY MANGLING GAP
// ============================================

// esbuild supported property mangling:
// esbuild: {
//   mangleProps: /^_/,
//   reserveProps: /^__/,
// }

// Oxc does not support property mangling.
// The options are not available.
// The output is larger if the project relied on them.

// ============================================
// PART 8: THE DECORATOR WORKAROUND
// ============================================

// Oxc does not yet support native decorator lowering.
// The workaround is to use a Babel or SWC plugin.
// vite.config.ts
import { defineConfig } from 'vite';
import babel from '@rolldown/plugin-babel';

export default defineConfig({
  plugins: [
    babel({
      // The Babel plugin handles the decorator transform.
      // Oxc handles the rest.
    }),
  ],
});

// ============================================
// PART 9: THE PERFORMANCE VERIFICATION
// ============================================

// The Oxc parser is 3x faster than SWC.
// The Oxc transformer is 4x faster than SWC and 40x faster than Babel.
// The Oxc minifier is the default in Vite 8.
// The build time should be lower than the esbuild-based build.
//
// The dev server startup is faster because the parser is faster.
// The production build is faster because the transformer and minifier are faster.

// ============================================
// PART 10: THE VERIFICATION CHECKLIST
// ============================================

// [ ] The esbuild option is renamed to oxc.
// [ ] The tsconfig JSX settings match the oxc.jsx settings.
// [ ] The minifier options are on rolldownOptions.output.minify.
// [ ] The snake_case casing is used for drop_console.
// [ ] The const enum usage is audited if isolatedModules is enabled.
// [ ] The property mangling options are audited if they were used.
// [ ] The decorator transform is handled by a plugin if needed.

The ten parts covered the renamed transform option, the JSX runtime mapping, the tsconfig sync, the minifier shorthand, the minifier options, the const enum edge case, the property mangling gap, the decorator workaround, the performance verification, and the checklist. The through-line is that the Oxc migration is a rename for the common case and a behavioral audit for the edge cases.


Quick Reference

The option renames

esbuildoxc
esbuildoxc
esbuild.jsxFactoryoxc.jsx.pragma
esbuild.jsxFragmentoxc.jsx.pragmaFrag
esbuild.jsx: 'automatic'oxc.jsx: { runtime: 'automatic' }
esbuild.jsx: 'transform'oxc.jsx: { runtime: 'classic' }

The minifier configuration

SettingLocationCasing
Enable minifierbuild.minify: 'oxc'—
Compression optionsbuild.rolldownOptions.output.minify.compresssnake_case
Drop consolecompress.drop_consolesnake_case

The performance gains

ToolComparisonSource
Parser3× faster than SWC
Transformer4× faster than SWC, 40× faster than Babel
MinifierDefault in Vite 8

The edge cases

Edge caseBehaviorFix
const enum with isolatedModulesNot inlined across filesUse regular enum or as const object
Property manglingNot supportedAccept larger output or report the gap
DecoratorsNot yet supported nativelyUse @rolldown/plugin-babel or @rollup/plugin-swc
jsxFactory mismatchBuild failureSync tsconfig.json and oxc.jsx

Best Practices

✅ Do This:

// Use the oxc option for transforms
oxc: { jsx: { runtime: 'automatic', importSource: 'react' } }   // ✅

// Use rolldownOptions for minifier options
rolldownOptions: { output: { minify: { compress: { drop_console: true } } } } // ✅

// Sync tsconfig and oxc.jsx
// "jsx": "react-jsx", "jsxImportSource": "react"                 // ✅

// Use snake_case for Oxc minifier options
compress: { drop_console: true }                                  // ✅

❌ Don’t Do This:

// Use camelCase for Oxc minifier options
compress: { dropConsole: true } // silently does nothing          // ❌

// Rely on const enum across files
const enum Status { Active = 1 } // not inlined                   // ❌

// Use property mangling
mangleProps: /^_/ // not supported                                 // ❌

// Assume the jsxFactory mapping is automatic
// The tsconfig and oxc.jsx must both be updated                   // ❌

Common Pitfalls

PitfallWhy It HappensFix
drop_console has no effectdropConsole (camelCase) was usedUse drop_console (snake_case)
JSX build failstsconfig.json and oxc.jsx disagreeSync the runtime and import source
const enum breaksisolatedModules is enabledUse regular enum or as const object
Decorators breakOxc does not support decorator loweringUse a Babel or SWC plugin
Property mangling ignoredOxc does not support itAccept the output size or report the gap

Real-World Examples

1. Rename esbuild to oxc

oxc: { jsx: { runtime: 'automatic' } }

2. Minifier shorthand

build: { minify: 'oxc' }

3. Minifier options

build: { rolldownOptions: { output: { minify: { compress: { drop_console: true } } } } }

4. tsconfig sync

{ "compilerOptions": { "jsx": "react-jsx", "jsxImportSource": "react" } }

5. const enum fix

const Status = { Active: 1, Inactive: 0 } as const;

6. Decorator workaround

plugins: [babel({ /* decorator transform */ })]

7. Property mangling gap

// No equivalent; output is larger

8. Performance measurement

time npm run build

9. JSX classic runtime

oxc: { jsx: { runtime: 'classic', pragma: 'h', pragmaFrag: 'Fragment' } }

10. Verification

npm run build # no JSX errors, no minifier errors

Visual

The Toolchain

┌──────────────────────────────────────────────────────────────┐
│  VITE 8 TOOLCHAIN                                             │
│                                                              │
│  Vite (orchestration)                                        │
│         │                                                    │
│         ▼                                                    │
│  Rolldown (bundling)                                         │
│         │                                                    │
│         ├──▶ Oxc Parser                                      │
│         ├──▶ Oxc Transformer                                 │
│         ├──▶ Oxc Resolver                                    │
│         └──▶ Oxc Minifier                                    │
│                                                              │
│  All five layers are maintained by VoidZero.                 │
│  The parser and transformer are shared with Oxlint.          │
└──────────────────────────────────────────────────────────────┘

The Transform Configuration

┌──────────────────────────────────────────────────────────────┐
│  esbuild → oxc MAPPING                                        │
│                                                              │
│  esbuild                      oxc                            │
│  ┌─────────────────────┐     ┌─────────────────────┐        │
│  │ jsxFactory          │────▶│ jsx.pragma          │        │
│  │ jsxFragment         │────▶│ jsx.pragmaFrag      │        │
│  │ jsx: 'automatic'    │────▶│ jsx: { runtime:     │        │
│  │                     │     │   'automatic' }     │        │
│  │ jsx: 'transform'    │────▶│ jsx: { runtime:     │        │
│  │                     │     │   'classic' }       │        │
│  └─────────────────────┘     └─────────────────────┘        │
│                                                              │
│  The jsxImportSource option maps to jsx.importSource.       │
│  The banner/footer options have no equivalent.               │
└──────────────────────────────────────────────────────────────┘

The Minifier Configuration

┌──────────────────────────────────────────────────────────────┐
│  TWO ENTRY POINTS, ONE MINIFIER                              │
│                                                              │
│  build.minify: 'oxc'                                         │
│  ┌─────────────────────┐                                    │
│  │ Enables the minifier│                                    │
│  │ with defaults       │                                    │
│  │ No compress options │                                    │
│  └─────────────────────┘                                    │
│                                                              │
│  build.rolldownOptions.output.minify                         │
│  ┌─────────────────────┐                                    │
│  │ Full configuration  │                                    │
│  │ compress: {         │                                    │
│  │   drop_console: true│                                    │
│  │ }                   │                                    │
│  └─────────────────────┘                                    │
│                                                              │
│  The rolldownOptions route is the full configuration.       │
│  The shorthand is not needed when the full route is used.   │
└──────────────────────────────────────────────────────────────┘

Summary

ItemValue
OxcRust-based parser, transformer, minifier, resolver
Replacesesbuild (transform and minify)
Transform optionoxc (was esbuild)
Minifier optionbuild.rolldownOptions.output.minify
Minifier casingsnake_case (drop_console)
Parser speed3× faster than SWC
Transformer speed4× faster than SWC, 40× faster than Babel
const enum behaviorNot inlined across files with isolatedModules
Property manglingNot supported
DecoratorsNot yet supported natively

Key takeaways:

  • Oxc is the language layer beneath Rolldown. It parses, transforms, resolves, and minifies. The parser and transformer are shared with Oxlint, which is why the same foundation powers the build and the lint pass . The configuration surface is the oxc option for transforms and rolldownOptions.output.minify for minifier options.
  • The transform option is a rename with edge cases. esbuild becomes oxc, jsxFactory becomes jsx.pragma, and the JSX runtime is configured through oxc.jsx.runtime. The tsconfig.json must match the oxc.jsx configuration, or the build fails .
  • The minifier options are on Rolldown, not on the oxc option. The build.minify: 'oxc' shorthand enables the minifier but does not expose the compression options. The full configuration is build.rolldownOptions.output.minify, and the option names are snake_case .
  • The edge cases are specific and documented. const enum is not inlined across files when isolatedModules is enabled. Property mangling is not supported. Decorators require a Babel or SWC plugin. A project that uses these features must audit them .
  • The performance gains are the reason for the swap. The parser is 3× faster than SWC, and the transformer is 40× faster than Babel. The gains compound across the build because every module goes through the parser and transformer .

Remember: Oxc is the compiler foundation that Vite 8 runs on. It replaces esbuild for transforms and minification, and it shares its parser and transformer with Rolldown and Oxlint. The migration is a rename for the common case and a behavioral audit for the edge cases. The transform options go on oxc, the minifier options go on rolldownOptions.output.minify, and the casing matters. The const enum and property mangling gaps are real; a project that uses them must adjust. The performance is the payoff, and it is the reason the swap happened.

Was this helpful?


Stop using slow, ad-bloated tool sites! 🤮

🔎 Search “KandZ Tools” on Google to use many professional utilities for free.

KandZ.me is the ultimate minimalist hub for:
✅ Finance (Mortgage, Interest, Inflation)
✅ Tech (Base64, JSON, Dev Suite, IP)
✅ Health (BMI, BMR, TDEE)
✅ Productivity (Timer, Workspace, QR)

⚡️ Fast & Private
🔒 No data leaves your device
💎 100% Free

🔗 Use it now: https://tools.kandz.me
🔖 Bookmark it—you’ll need it later!