CodeWorlds
Back to collections
Guide19 min readCodeWorlds Team

Rolldown, a Rust bundler in place of Rollup

Rolldown is a Rust bundler with a Rollup-compatible plugin API. Version 1.2.5, the 1.0 stability contract, Vite 8, and where compatibility ends.

Rolldown, a Rust bundler in place of Rollup

Rolldown is a bundler written in Rust that exposes Rollup's plugin interface with a feature scope closer to esbuild. The current version is 1.2.5, released on 19 August 2026, the licence is MIT, and the rolldown/rolldown repository has around 13.9 thousand stars. Since version 8 it is the default and only bundler in Vite.

What Rolldown actually does

The scope is narrower than the phrase "build tool" suggests. Rolldown takes a module graph, resolves imports, removes unused code and writes output chunks. There is no dev server, no hot module replacement in standalone mode, and no test runner.

What separates it from Rollup is what sits inside without plugins. TypeScript and JSX transforms are built in and run through Oxc, together with syntax lowering down to ES2015. Module resolution is handled by oxc-resolver, aligned with Node and TypeScript behaviour, and it reads compilerOptions.paths from the file named by the tsconfig option. A mixed ESM and CommonJS module graph works without @rollup/plugin-commonjs, following esbuild's semantics. On top of that come transform.define, transform.inject and a minifier from the Oxc family.

In practice this means five popular Rollup plugins stop being necessary: @rollup/plugin-alias is replaced by the resolve.alias option, @rollup/plugin-node-resolve and @rollup/plugin-commonjs by built-in features, @rollup/plugin-inject by the transform.inject option, and @rollup/plugin-json by JSON handling in the core.

What Rolldown does not do matters just as much when planning a pipeline. It does not check types, so tsc --noEmit stays a separate step, exactly as with TypeScript in any other setup. It does not generate declaration files; the documentation points library authors to tsdown, and the npm registry carries a separate rolldown-plugin-dts plugin at version 0.28.2. It does not shim Node built-ins under platform: 'browser', which has to be added through the rolldown-plugin-node-polyfills plugin. It does not check code style, which is what oxlint and Biome are for. It does not manage a monorepo cache, which is Turborepo territory.

Version, licence and project status

Version numbers and declared readiness drift apart so often in this class of tooling that it has to be checked separately. Here they do not drift apart, but the contract is narrower than the word "stable" suggests.

Rolldown 1.0 shipped on 7 May 2026 and the announcement speaks plainly of stability and production readiness. The ^1.0.0 range is locked: option names, types and plugin hook signatures stay backward-compatible. The exception covers features marked experimental, and the documentation for the experimental option states it without hedging: those features may change behaviour without a major version bump.

The second caveat matters more for anyone putting Rolldown in the middle of a build pipeline. The 1.0 announcement says output behaviour will keep changing: dead code elimination, chunking and constant inlining heuristics will keep improving, and option defaults may shift in minor releases. The authors state this does not change the runtime behaviour of the generated code, and that is how it should be read: the interface is frozen, the number and names of output files are not.

Releases come thick and fast. Versions 1.2.0 through 1.2.5 appeared between 15 July and 19 August 2026, roughly one a week. The last change on the main branch dates from 21 August 2026, the repository has around a thousand forks, 256 open issues and 131 open pull requests.

The licence looks the same from three independent directions, which is not the rule for tools of this class. The LICENSE file in the repository and in the published package carries the full MIT text with the note "Copyright (c) 2024-present VoidZero Inc. & Contributors". The license field in the npm registry reads MIT. The unpacked rolldown@1.2.5 package contains exactly five entries: LICENSE, README.md, THIRD-PARTY-LICENSE, a bin directory and a dist directory, totalling about 839 kilobytes of plain JavaScript. The THIRD-PARTY-LICENSE file holds the MIT texts of Rollup from 2017 and esbuild from 2020, by Evan Wallace, because parts of both projects were reimplemented. There is no split licence here, no revenue threshold and no conversion date. The whole thing is permissive, redistribution included.

The native code lives outside that package. Rolldown declares fifteen optional dependencies carrying binaries, pinned exactly to 1.2.5, one per platform. The @rolldown/binding-darwin-arm64 package alone unpacks to 17,070,467 bytes, about 17.1 megabytes, so a real installation is not 839 kilobytes but close to 18 megabytes for a single platform. Installing while skipping optional dependencies will not give you a working program.

The registry also carries 29 versions flagged as deprecated, all with the message legacy versions, the oldest of them 0.1.0 from 1 January 2017, predating the current project entirely. The name was inherited from an older, unrelated package. No deprecated version hangs on the latest tag, which points at 1.2.5. The engines field requires Node ^20.19.0 || >=22.12.0, exactly like Vite 8.

Shipping Rolldown as a Rust library is a separate matter. The documentation gives three rules and all of them are discouraging: the crates do not follow semantic versioning and may introduce breaking changes in any release, no documentation is produced for them, and issues affecting only the crates are closed. The npm package is the reference point.

There is no paid variant and no pricing to check. VoidZero, the company behind the project, sells a separate product called Vite+, currently in beta, and its home page publishes no prices in the raw HTML. The same page carries an announcement that VoidZero is joining Cloudflare, which for a tool at the core of a build pipeline is information about ownership rather than about features.

Rolldown, rolldown-vite and Vite 8

Three names travel together and get mixed up in descriptions written in 2025. They are three distinct npm packages and only one of them is worth installing deliberately today.

The rolldown package is the standalone bundler described here, at version 1.2.5. You install it when building a library or bundling code without Vite.

The rolldown-vite package was a temporary Vite variant with the bundler swapped out, published in May 2025 as a technical preview to gather feedback before the real swap. Development stopped at version 7.3.1 on 9 January 2026. What the version number does not show matters more: all 92 versions of that package are flagged as deprecated in the registry, and the message on 7.3.1 says the package exists solely to migrate from Vite 7 to Vite 8. There is no reason to reach for it in a new project.

The vite package has had Rolldown as its default and only bundler since 8.0.0 on 12 March 2026, with no enabling flag. The dates are worth tracing, because they say more than the declarations: Vite 8.0.0 declared rolldown at version 1.0.0-rc.9, so stable Vite 8 shipped eight weeks before stable Rolldown, and for that stretch millions of projects were building on a release candidate. The current Vite 8.2.2, from 20 August 2026, declares rolldown in the ~1.2.4 range.

That range hides a practical trap. Rolldown is a regular dependency of Vite rather than a peer dependency, so installing Vite gives you one specific copy of the bundler. Adding rolldown to devDependencies next to Vite 8.2.2 works without conflict only for 1.2.4 and 1.2.5, because that is what ~1.2.4 allows. Pinning 1.1.x puts two copies of the bundler and two sets of native binaries in the tree, while plugins still run through the one Vite picked. Rolldown itself declares no peer dependencies at all. The plugins around it do: rolldown-plugin-dts at version 0.28.2 requires rolldown in the ^1.2.0 range, so it will not work on the 1.1 branch.

Rollup compatibility and where it ends

The documentation speaks of an interface that is "almost fully compatible", and that phrasing is useless without a list. The list exists and it is short.

Unsupported hooks come to three entries. From the build phase, shouldTransformCachedModule is missing. From the output generation phase, resolveImportMeta and renderDynamicImport are missing. Each has an open issue in the repository, numbered 4389, 1010 and 4532 respectively.

The plugin context lacks three things Rollup offers: there is no cache, no setAssetSource and no getWatchFiles. The rest is in place, including this.meta, emitFile, load, resolve, parse, getModuleIds, getModuleInfo and addWatchFile.

Four behavioural differences cost more than the missing hooks, because they raise no error and simply change the result. First, every output is generated separately, so the outputOptions hook runs before the build hooks, the reverse of Rollup, and the build hooks themselves run once per output. Second, closeBundle runs only if generate() or write() was called at least once. Third, in watch mode the options hook runs once, when the watcher is created, rather than on every rebuild. Fourth, writeBundle is sequential by default, so plugins setting sequential: true no longer change anything by it.

A fifth difference concerns source maps and breaks the build immediately. Rollup does not check a plugin's map against its own sources and names; a mapping pointing at a missing source is silently dropped. Rolldown checks every index while converting the map to its internal representation, so a map Rollup accepts can stop the build with:

Code
TEXT
Failed to convert json sourcemap to struct
Reference to non-existing source at position 1

A separate trap applies to plugins working in the transform hook. The internal TypeScript and JSX transform to JavaScript happens after those hooks, not before, so a plugin receives code with TypeScript syntax in it. There are two ways out: this.parse with the lang option, or the transform function from rolldown/utils, with the second one costing an extra pass.

File references carry a new prefix. Emitted assets are referenced through import.meta.ROLLDOWN_FILE_URL_referenceId, and import.meta.ROLLUP_FILE_URL_referenceId is accepted as a compatibility alias.

Is there an official list of plugins that do not work, like the eight Webpack plugins tracked on the Rspack side? Not in that form. There is issue number 819, titled "[Tracking] Rollup Plugin Compat Status", but it was opened in April 2024 and closed as not planned, and its contents are misleading today: it lists resolveFileUrl and this.meta as unsupported, although the 1.2.5 documentation describes both as working, and it calls minification a work in progress, although the output.minify option is documented. The only current record of incompatibilities is the "Unsupported Hooks" and "Notable Differences from Rollup" sections on the Plugin API page. The absence of a maintained plugin list is a real gap: checking your own plugin set falls to you.

Why bother, given esbuild exists

The answer is not "because it is faster". It is "because one pipeline replaces two".

Vite up to and including version 7 split the work. esbuild pre-bundled dependencies and transformed TypeScript and JSX in dev mode, while Rollup built the production bundle. That meant two parsers, two module resolution mechanisms, two plugin systems and a layer of glue code holding it together. The consequence was a whole class of "works locally, breaks after the build" reports, because dev-mode code went through a different tool than production code. Plugins written for Rollup took no part in dependency pre-bundling, and esbuild plugins took no part in the production build.

Rolldown replaces both tools with one. That is the point, and the speed-up is a side effect of the language choice. For a team maintaining its own plugins, it means one set of hooks covers both phases.

That leaves the question of why not use esbuild for both roles. The reason is ecosystem-shaped: esbuild has its own narrow plugin interface and less control over chunking, while Vite plugins have been written against Rollup's interface for years. Rolldown takes the plugin interface from Rollup, the feature scope from esbuild, and adds things neither has, including webpack-style manual chunking through output.codeSplitting.groups.

The numbers deserve a note on provenance, because they come from the authors. The benchmark in the rolldown/benchmarks repository, run on an ubuntu-latest machine, with data labelled 21 December 2025, bundles 19 thousand modules, namely 10 thousand React components in JSX and 9 thousand JavaScript files from the iconify set, with minification and source maps. The results: Rolldown 1.61 seconds, esbuild 1.70 seconds, Rspack 4.07 seconds, and the Rollup plus esbuild pair 40.10 seconds. That is roughly 25 times faster than the arrangement Vite used before, and roughly 5 percent faster than esbuild. Elsewhere the documentation gives a range of 10 to 30 times faster than Rollup alone, and those two figures describe different configurations, so they should not be conflated. The 1.0 announcement additionally cites build times cut by 57 percent at Ramp, by up to 38 percent at Mercedes-Benz.io and by 64 percent at Beehiiv, with no published methodology, so treat them as vendor claims.

Configuration and running it

The config file is called rolldown.config with a js, mjs, cjs, ts, mts or cts extension and sits in the root directory. By default it is loaded by bundling it with Rolldown itself, which corresponds to configLoader: 'bundle'. The native variant imports the file directly and requires a runtime that handles TypeScript on its own, meaning Node 22.18 or newer, Bun, Deno, or a registered loader. The documentation says native is planned to become the default at some point.

Code
Bash
# install pinned to an exact version
npm install --save-dev --save-exact rolldown

# build from the config file
npx rolldown -c

# TypeScript config loaded without bundling it first
npx rolldown -c rolldown.config.ts --configLoader native

# watch mode
npx rolldown -c --watch

# minification enabled from the command line
npx rolldown -c --minify

# turning a boolean flag off: the --no- prefix, never "false" as a value
npx rolldown -c --no-codeSplitting

# setting a nested field with dot notation
npx rolldown -c --codeSplitting.minSize 30000

# variables passed into the config file via process.env
npx rolldown -c --environment INCLUDE_DEPS,BUILD:production

In watch mode the command line sets the ROLLDOWN_WATCH and ROLLUP_WATCH environment variables, but a plugin should check this.meta.watchMode, because that works independently of how the build was started.

Below is a configuration using fields verified against the 1.2.5 documentation.

Code
TypeScript
import { defineConfig } from 'rolldown'

export default defineConfig({
  input: 'src/main.ts',
  platform: 'browser',
  tsconfig: './tsconfig.json',
  transform: {
    define: { IS_PROD: 'true' },
    decorator: { legacy: true }
  },
  optimization: {
    inlineConst: { mode: 'smart', pass: 1 },
    pifeForModuleWrappers: true
  },
  checks: {
    circularDependency: true,
    cannotCallNamespace: true
  },
  output: {
    dir: 'dist',
    format: 'esm',
    minify: true,
    codeSplitting: {
      minSize: 20000,
      groups: [
        { name: 'react-vendor', test: /node_modules[\\/]react/, priority: 20 },
        { name: 'vendor', test: /node_modules/, priority: 10 },
        { name: 'common', minShareCount: 2, minSize: 10000, priority: 5 }
      ]
    }
  }
})

The platform option accepts node, browser or neutral and defaults to node for the cjs format and browser for the others. The optimization.inlineConst option defaults to { mode: 'smart', pass: 1 }, meaning constants are inlined only in conditions, ternary operators and logical expressions. The optimization.pifeForModuleWrappers option is on by default and wraps module wrappers in parentheses so the V8 engine compiles them eagerly, at a slight cost in bundle size.

Inside Vite the same set of options is passed through build.rolldownOptions.

Code
TypeScript
import { defineConfig } from 'vite'

export default defineConfig({
  build: {
    rolldownOptions: {
      output: {
        codeSplitting: {
          groups: [{ name: 'vendor', test: /node_modules/ }]
        }
      }
    }
  }
})

Hook filters are a mechanism Rollup does not have, and on larger projects they matter for build time. A plugin declaring a filter on id, code or moduleType does not cross the Rust to JavaScript boundary for modules the filter rejects. A plugin without filters of its own can be wrapped with the withFilter function.

Code
JavaScript
import fs from 'node:fs'
import path from 'node:path'
import { defineConfig } from 'rolldown'
import { withFilter } from 'rolldown/filter'
import yaml from '@rollup/plugin-yaml'

function svgAssetPlugin() {
  return {
    name: 'svg-asset',
    resolveId: {
      filter: { id: /\.svg$/ },
      handler(source, importer) {
        return path.resolve(path.dirname(importer), source)
      }
    },
    load: {
      filter: { id: /\.svg$/ },
      handler(id) {
        const referenceId = this.emitFile({
          type: 'asset',
          name: path.basename(id),
          source: fs.readFileSync(id)
        })
        return `export default import.meta.ROLLDOWN_FILE_URL_${referenceId};`
      }
    }
  }
}

export default defineConfig({
  plugins: [
    svgAssetPlugin(),
    withFilter(yaml(), { transform: { id: /\.yaml$/ } })
  ]
})

Compared with Rollup, esbuild and Rspack

The versions in the table headers come from the latest tags in the npm registry as of 22 August 2026.

TraitRolldown 1.2.5Rollup 4.62.5esbuild 0.28.2Rspack 2.1.10
Implementation languageRustJavaScriptGoRust
Plugin interfaceRollup'sown, the reference oneown, narrowWebpack's
TypeScript and JSX transformbuilt in, Oxcvia pluginbuilt inbuilt in, SWC
CommonJS interopbuilt invia pluginbuilt inbuilt in
Manual chunkingoutput.codeSplitting.groupsmanualChunksnoneoptimization.splitChunks
Minificationbuilt in, defaults to dce-onlyvia pluginbuilt in, on demandbuilt in, SWC
LicenceMITMITMITMIT

The table does not settle the choice, because the choice is usually settled by the plugin ecosystem you already use. If those are Rollup or Vite plugins, Rolldown is the natural path. If they are Webpack plugins, look at Rspack.

Common mistakes

The first concerns minification. The output.minify option defaults to 'dce-only', which removes dead code but does not shorten identifiers. Building a project with npx rolldown -c without setting that option explicitly produces a larger result than you expect, and it is easy to draw the wrong conclusion about the tool from it.

The second is turning boolean flags off on the command line. Writing --minify false errors out, because the value is read as the string "false". The correct form is --no-minify, following Rollup's convention.

The third is adding rolldown to a project that already has Vite 8, in order to "get a newer version". The ~1.2.4 range in Vite 8.2.2 allows only 1.2.4 and 1.2.5; anything outside it puts two copies of the bundler in the dependency tree and two sets of native binaries, and Vite will use its own anyway.

The fourth is a plugin in the transform hook that parses the code it receives as plain JavaScript. It will receive TypeScript or JSX, because the internal transform runs after that hook.

The fifth is a plugin without hook filters in a project with thousands of modules. Every module then crosses the Rust to JavaScript boundary, and the gain from a native bundler melts away. Wrapping it with withFilter on the consumer side takes one line.

The sixth is assuming closeBundle always runs. It runs only if you call generate() or write() at least once, so cleanup code hanging off that hook can silently never fire under unusual programmatic use.

The seventh is installing while skipping optional dependencies. Without the @rolldown/binding-* package for your platform you get a JavaScript package with no engine. On platforms outside the prebuilt binary list, the Wasm variant remains, installed separately with npm install --cpu wasm32 --os wasip1-threads.

The eighth is reaching for the Rust crate instead of the npm package, in the belief that it is the same thing with the same guarantees. It is not: the crates do not follow semantic versioning, have no documentation, and issues affecting only them are closed.

FAQ

Is Rolldown 1.x suitable for production?

Yes, and that is the authors' own statement from the 1.0 announcement of 7 May 2026, not an inference. The documentation carries no warning against production use, and neither does the README in the published package. The contract has limits, though: option names, types and plugin hook signatures are frozen, while chunking heuristics and option defaults may change in minor releases, and features marked experimental may change behaviour without a major version bump.

What is the difference between rolldown and rolldown-vite?

rolldown is the standalone bundler at version 1.2.5. rolldown-vite was a temporary Vite variant with the bundler swapped out, released in May 2025 as a technical preview; it stopped at 7.3.1 and all 92 versions in the npm registry are flagged as deprecated, with a message directing you to migrate to Vite 8. In Vite 8, Rolldown is the default and only bundler, with no flag involved.

Will my Rollup plugins work unchanged?

Most will, but the list of exceptions is concrete. Three hooks do not work: shouldTransformCachedModule, resolveImportMeta and renderDynamicImport. The plugin context lacks cache, setAssetSource and getWatchFiles. On top of that come five behavioural differences, including per-output generation and stricter source map validation. There is no maintained list of broken plugins; issue 819 is closed and out of date.

Does Rolldown replace esbuild inside Vite entirely?

In Vite 8 it does: Rolldown took over both dependency pre-bundling and the production build, and esbuild dropped to an optional peer dependency in that package, declared in the ^0.27.0 || ^0.28.0 range. Outside Vite, esbuild remains a separate tool with a different plugin interface and can still be the better choice where only single-file transformation matters.

Will Rolldown generate TypeScript declaration files?

Not on its own. The documentation points library authors to the tsdown tool, and the npm registry carries a separate rolldown-plugin-dts plugin at version 0.28.2, which requires rolldown in the ^1.2.0 range. Type checking still requires running the TypeScript compiler separately.

How much disk space does an installation take?

The rolldown@1.2.5 package is about 839 kilobytes of plain JavaScript, but the engine sits in a separate package holding the binary for your platform. The @rolldown/binding-darwin-arm64 variant at the same version unpacks to 17,070,467 bytes, about 17.1 megabytes, so count on close to 18 megabytes per platform in practice. For container images built from scratch, that is a visible line item.

Read next

We use cookies to enhance your experience on the site