cheat sheet
rollup
Daily-driver reference for rollup — CLI commands, multi-format output, plugin chain patterns, library publishing config.
rollup — CLI & plugins
What it is
rollup is the library-focused JS bundler — clean tree-shaken ESM/CJS/UMD output, a plugin model that became the standard for the ecosystem (Vite plugins are Rollup-plugin-compatible). For libraries you publish, this is still the default. For apps, use Vite (which wraps Rollup for prod).
For full ecosystem context, see packages-npm/npm-rollup. This page covers the CLI and plugin patterns.
Install
npm install -D rollup
# common companions
npm install -D @rollup/plugin-node-resolve @rollup/plugin-commonjs @rollup/plugin-typescript tslib
npm install -D @rollup/plugin-terser rollup-plugin-dts
Output: rollup CLI in node_modules/.bin/.
Day-to-day commands
| Command | What it does |
|---|---|
rollup -c | Build using rollup.config.js |
rollup -c rollup.lib.config.js | Use a specific config |
rollup -c -w | Watch mode |
rollup -i src/index.js -o dist/out.js -f esm | CLI-only build (no config) |
rollup -c --silent | Suppress non-error output |
rollup -c --environment NODE_ENV:production | Pass env vars (read via process.env) |
rollup -c --bundleConfigAsCjs | Read rollup.config.js as CJS |
rollup.config.js is loaded as ESM by default if your package.json has "type": "module"; otherwise CJS. You can also name files rollup.config.mjs / rollup.config.cjs to force a mode.
Common scenarios
Library bundle — ESM + CJS
// rollup.config.js
import typescript from "@rollup/plugin-typescript";
import nodeResolve from "@rollup/plugin-node-resolve";
import commonjs from "@rollup/plugin-commonjs";
export default {
input: "src/index.ts",
output: [
{ file: "dist/index.mjs", format: "es" },
{ file: "dist/index.cjs", format: "cjs", exports: "named" },
],
external: ["react"],
plugins: [nodeResolve(), commonjs(), typescript()],
};
npx rollup -c
Output:
src/index.ts → dist/index.mjs, dist/index.cjs...
created dist/index.mjs, dist/index.cjs in 412ms
Match package.json:
{
"main": "./dist/index.cjs",
"module": "./dist/index.mjs",
"exports": {
".": {
"import": "./dist/index.mjs",
"require": "./dist/index.cjs"
}
}
}
Plugin chain — TS + JSX + replace + minify
import typescript from "@rollup/plugin-typescript";
import nodeResolve from "@rollup/plugin-node-resolve";
import commonjs from "@rollup/plugin-commonjs";
import replace from "@rollup/plugin-replace";
import terser from "@rollup/plugin-terser";
export default {
input: "src/index.tsx",
output: { file: "dist/bundle.js", format: "es", sourcemap: true },
external: ["react", "react-dom"],
plugins: [
nodeResolve({ extensions: [".js", ".ts", ".tsx"] }),
commonjs(),
replace({
"process.env.NODE_ENV": JSON.stringify("production"),
preventAssignment: true,
}),
typescript({ jsx: "react-jsx" }),
terser(),
],
};
Plugin order is top-to-bottom (opposite of webpack loaders). replace before typescript substitutes in TS source; after substitutes in compiled JS.
Multi-format output
export default {
input: "src/index.ts",
output: [
{ file: "dist/my-lib.mjs", format: "es" },
{ file: "dist/my-lib.cjs", format: "cjs", exports: "named" },
{
file: "dist/my-lib.umd.js",
format: "umd",
name: "MyLib",
globals: { react: "React", "react-dom": "ReactDOM" },
},
],
external: ["react", "react-dom"],
};
Banner / footer
import pkg from "./package.json" with { type: "json" };
export default {
output: {
file: "dist/index.mjs",
format: "es",
banner: `/*! ${pkg.name} v${pkg.version} | ${pkg.license} */`,
},
};
Bundle .d.ts files
// rollup.dts.config.js
import dts from "rollup-plugin-dts";
export default {
input: "dist/types/index.d.ts",
output: { file: "dist/index.d.ts", format: "es" },
plugins: [dts()],
};
Two-step library build:
{
"scripts": {
"build:types": "tsc --emitDeclarationOnly --outDir dist/types",
"build:bundle": "rollup -c",
"build:dts": "rollup -c rollup.dts.config.js",
"build": "npm run build:types && npm run build:bundle && npm run build:dts"
}
}
Preserve modules (per-file output)
output: {
dir: "dist",
format: "es",
preserveModules: true,
preserveModulesRoot: "src",
}
Mirrors src/ structure under dist/. Best for libraries where consumers do their own tree-shaking.
Watch mode
npx rollup -c -w
Output:
rollup v4.21.0
bundles src/index.ts → dist/index.mjs...
created dist/index.mjs in 412ms
[1500] waiting for changes...
Useful flags
| Flag | What it does |
|---|---|
-c, --config <path> | Path to config file |
-w, --watch | Watch mode |
-i, --input <file> | Entry point (CLI-only build) |
-o, --file <file> | Output file |
-f, --format <fmt> | Output format (es, cjs, umd, iife, amd, system) |
-n, --name <name> | Global name for UMD/IIFE builds |
-e, --external <list> | Comma-separated external IDs |
-m, --sourcemap | Emit sourcemap |
--silent | Suppress non-error output |
--bundleConfigAsCjs | Force-load config as CJS |
--environment <list> | Set env vars (NODE_ENV:production,DEBUG:true) |
--treeshake.<flag> | Tweak tree-shaking heuristics |
Configuration
Beyond config files, rollup honours config-as-function for dynamic settings:
import { defineConfig } from "rollup";
export default defineConfig((cmdArgs) => ({
input: "src/index.ts",
output: {
file: cmdArgs.configMinify ? "dist/index.min.js" : "dist/index.js",
format: "es",
},
}));
npx rollup -c --configMinify
Output:
src/index.js → dist/...
created dist in 612ms
defineConfig exists for IDE autocomplete; vanilla export default { ... } works the same.
Common output options
| Option | Purpose |
|---|---|
file | Single-file output |
dir | Multi-file output (chunks) |
format | es, cjs, umd, iife, amd, system |
name | Global name (UMD/IIFE only) |
globals | Map of external → global var (UMD/IIFE) |
banner / footer | Prepend/append strings |
sourcemap | true, "inline", "hidden", false |
exports | "auto", "default", "named", "none" |
preserveModules | Per-file output (skip bundling) |
Common pitfalls
Could not resolve "X" from "src/Y.js". Missing@rollup/plugin-node-resolve, or the module is meant to be external (add toexternal).'default' is not exported by "node_modules/foo". CJS dep lacks a default export. Add@rollup/plugin-commonjswithrequireReturnsDefault: "auto".Mixing named and default exportswarning. Setoutput.exports: "named"explicitly, or refactor source to use only one style.- Tree shaking removed a side-effecting import. Mark the file in
package.json"sideEffects": ["./src/register.ts"]. process.env.NODE_ENVun-substituted. Add@rollup/plugin-replacewithpreventAssignment: true.- Plugin order matters.
replacebefore TS → substitute in source. After → substitute in compiled output. .d.tsper file instead of one consolidated file. Use therollup-plugin-dtstwo-step pattern above.
See also
- Packages: npm-rollup — versioning, security, ecosystem
- JavaScript: modules — ESM/CJS/UMD interop
- JavaScript: vite — for application bundling