Library / SDK
rollup/rollup avatar
rollup/rollup

Rollup's core is now Rust, and tree shaking depends on ES module imports

Next-generation ES module bundler

26,305 stars1,905 forksJavaScriptNOASSERTION

At a glance

What is it?
The ES module bundler still reads like the tool you used five years ago, with the same three command lines. Underneath, version 4.67.4 builds a Rust core through napi plus a WebAssembly path, and ships per-platform binaries from a separate package. The behaviour that actually constrains you is unchanged: static analysis only works while everything in your graph is an ES module.
Who is it for?
Rollup fits a library author who needs one clean ES module output, or an application team whose dependency graph is entirely ES modules and wants the unused exports actually removed. It does not fit a codebase that still pulls in CommonJS, because the README shows a CommonJS require bringing in the entire object rather than one function, and it does not fit a platform outside the twenty-six the native binaries target.
Can I use it commercially?
Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
Is it still maintained?
Yes. The repository received new commits within the last day.
What is it written in?
Mainly JavaScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on November 14, 2026, and from our analysis. They are not legal advice.

From daily snapshots

Star history

  • rollup/rollup26,305 ★ · -4
Star history
Repository2026-09-282026-11-14
rollup/rollup26.3k26.3k

-4 Stars in the last 47 days, measured from the daily GitHub snapshot. Compare with other projects

Editorial analysis

The three documented commands are the whole quick start

Installation is a global npm install, and everything after that is a format flag:

bash
npm install --global rollup

Assuming an entry point named `main.js` and an output called `bundle.js`, the documented invocations differ only in target environment. For a browser, a self-executing function:

bash
rollup main.js --format iife --name "myBundle" --file bundle.js

For Node.js, a CommonJS module, which needs no name because CommonJS has no global scope to expose one to. For both, UMD, which does require a bundle name:

bash
rollup main.js --format umd --name "myBundle" --file bundle.js

That the interface has not moved is the point of the tool. It is used through a command line with an optional configuration file, or through a JavaScript API, and `rollup --help` lists the rest. Two starter repositories exist, one for libraries and one for applications, which is the fastest way to see a realistic configuration rather than a minimal one.

The formats are the compatibility strategy. Rollup consumes standardized ES modules and can emit optimized ES modules for environments that support them, or compile down to CommonJS, AMD, or an IIFE-style script for environments that do not. A project written as ES modules can therefore still run on a browser with no native module support.

Tree shaking is static analysis of imports, which is not what a minifier does

This is the mechanism worth understanding, because it explains both the benefit and the ceiling.

Rollup statically analyzes the code you import and excludes anything not actually used. The README contrasts this with CommonJS, where the entire tool or library must be imported. Under CommonJS the whole object comes in and you pick a property off it at runtime. Under an ES module you import the one named function, and the bundler can see from the syntax alone that the rest of the module is unreachable:

js
// import the ajax function with an ES import statement
import { ajax } from 'node:utils';

The README is explicit that this is far more effective than running an automated minifier over compiled output, and the reason is a difference in what is available. A minifier sees a finished program and can drop unreferenced variables, but it cannot know that a function is never called if the call could be constructed at runtime. A bundler sees the import graph before any of that.

The ceiling follows directly. Tree shaking is a consequence of the `import` and `export` syntax being static, so anything that hides its shape behind a dynamic lookup, a side effect, or a runtime require is opaque to it. That is why the next section's compatibility note matters more than it first appears.

One CommonJS dependency disables tree shaking for that part of your graph

The compatibility section states the problem in one sentence: Rollup can import existing CommonJS modules through a plugin. That is the whole solution, and it is also the whole limitation.

A CommonJS module exports its contents by assigning to an object at runtime. A bundler reading ES module syntax has no way to know which properties a consumer will reach for, so it has to keep the entire module. The README's own comparison makes the size difference visible: with CommonJS, the entire object is imported, and with ES modules, only the one function.

So the practical effect is that tree shaking is a property of your dependency graph rather than of your own code. A project with clean ES module dependencies gets a small bundle. A project with one legacy CommonJS package in the middle gets that package whole, plus everything it pulls in, and the bundle looks like tree shaking silently failed.

The second compatibility note compounds this. To publish, you compile to UMD or CommonJS and point the `main` field in `package.json` at that build, and if you also add a `module` field, then ES-module-aware tools such as Rollup and webpack import the ES module version instead. A consumer whose bundler does not understand the `module` field gets your CommonJS build, which cannot be tree shaken, which means your careful authoring bought them nothing. The README recommends a reference for the field layout rather than describing it further.

The core is built in Rust and the binary comes from a separate package

The published package is JavaScript, and the tree says otherwise. There is a `rust/` directory, a `rust-toolchain.toml`, `native.js`, `native.wasm.js`, `native.d.ts`, a `wasm/` output directory and a `typings/` directory, and the build script runs both a wasm-pack build and a napi build.

The manifest declares an napi configuration with a `binaryName` of `rollup` and, importantly, a separate `packageName`:

json
"napi": {
  "binaryName": "rollup",
  "packageName": "@rollup/rollup"
}

That second field is the mechanism: the compiled native binary is not in the `rollup` package at all, it lives in `@rollup/rollup` and is resolved for your platform at install time. The `targets` list next to it enumerates twenty-six platform triples, covering aarch64 and x86_64 on Darwin, Linux and Windows, plus armv7, i686, loongarch64, powerpc64le, riscv64gc and s390x, most with both `gnu` and `musl` Linux variants, FreeBSD, OpenBSD, Android, and aarch64 OpenHarmony.

The second path is WebAssembly, built with wasm-pack, which is what `native.wasm.js` loads. Two loaders at the root of the repository is the visible cost of supporting both a native and a portable runtime.

The practical consequence is about your platform rather than your code. On a target in that list, install pulls a matching prebuilt binary.

patches/, audit-resolve.json and five changelog files

A few things in the repository root say more about how the project is run than the feature documentation does.

There is a `patches/` directory, which in this ecosystem means local modifications applied to dependencies rather than upstream fixes, and an `audit-resolve.json` that overrides how a dependency audit resolves particular packages. Both are maintenance decisions that keep a release shippable, and both are places to look if you ever need to know why a dependency behaves differently from its published version.

The changelog is split. There is a `CHANGELOG.md` and then `CHANGELOG-0.md` through `CHANGELOG-3.md`, which is what a major-version history looks like when it outgrows one file. Version 4 is in progress, so the entries you want for current releases are in the unnumbered file and the numbered ones are the archive.

There is also `ARCHITECTURE.md` and `CLAUDE.md` alongside `AGENTS.md`, so the project keeps a written architecture description and instructions for coding agents. Tooling around them is conventional and modern: husky with lint-staged, Prettier, ESLint with a flat config, markdownlint, nyc for coverage, codecov, Renovate for dependency updates, and a `rollup.config.ts` written in TypeScript.

On licensing, note that there are two files, `LICENSE.md` and `LICENSE-CORE.md`, and the repository carries no licence identifier that automated tooling recognises. If you are redistributing a build, read both and find out which one covers the part you are shipping.

Webpack and Rollup solve the same problem from different starting points

Rollup's own documentation names webpack as a peer rather than a rival, and reading how it does that is instructive. The README says that if your `package.json` has a `module` field, ES-module-aware tools like Rollup and webpack will import the ES module version directly. Webpack appears as something that understands the same metadata, not as something you must migrate away from.

The difference in approach is where the analysis happens. Rollup treats the input as a set of modules whose exports are known from syntax, and the output is a single file assembled from the reachable set. That model is why the output is compact, why the format options are small, and why CommonJS is the thing that breaks it. A tool built around a broader module system, with its own loaders for assets, transforms and non-JavaScript files, starts from a wider definition of what a module is and pays for that flexibility in output shape.

The framing that decides it is simple. If you publish a library and want the smallest, cleanest ES module output with no runtime, Rollup is the tool the documentation here is written for. If you are assembling an application with asset loaders and transforms, a bundler with that wider scope is the one that fits, and using it alongside Rollup for the library half is a normal arrangement rather than a contradiction.

Editorial conclusion

Rollup fits a library author who needs one clean ES module output, or an application team whose dependency graph is entirely ES modules and wants the unused exports actually removed. It does not fit a codebase that still pulls in CommonJS, because the README shows a CommonJS require bringing in the entire object rather than one function, and it does not fit a platform outside the twenty-six the native binaries target. Verify first by building your entry point and checking the output for modules you never imported, since that test tells you in one minute whether the main benefit is actually active for you.

Frequently asked questions

How do I install Rollup?

Run npm install --global rollup, then invoke it through the command line with an optional configuration file or through the JavaScript API. Run rollup --help for the full option list. The compiled native binary is not inside the rollup package: it is resolved at install time from a separate package named @rollup/rollup for your platform.

how to use rollup plugin visualizer

The project's own README does not document a bundle visualizer plugin. What it covers is the plugin mechanism for importing CommonJS modules, which points at the rollup plugins repository, and the command line surface, where the documented flags are the entry point, the output format, the bundle name and the output file. A visualizer would be added through the configuration file rather than the command line.

What does Rollup do that a minifier cannot?

Rollup statically analyzes the import graph before compiling, so an unused named export is never included. A minifier works on finished output and can only drop variables it can prove are unreferenced, which it cannot do when a call could be constructed at runtime. That is why the documentation says explicit import and export statements make this vastly more effective than detecting unused variables in compiled code.

Official sources

  1. Issues
  2. Project website
  3. README
  4. Releases
  5. rollup/rollup on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/rollup-rollup.svg)](https://hysenlabs.com/projects/rollup-rollup)

Star history chart for your README

markdown
[![Star history](https://hysenlabs.com/chart/rollup-rollup.svg)](https://hysenlabs.com/projects/rollup-rollup)

Was this useful?