<!-- PkgPulse AI-readable guide source -->
<!-- Canonical: https://www.pkgpulse.com/guides/rollup-vs-vite-2026 -->
<!-- Raw Markdown: https://www.pkgpulse.com/guides/rollup-vs-vite-2026/raw.md -->
<!-- Source path: content/guides/rollup-vs-vite-2026.mdx -->

---
og_image: "/images/guides/rollup-vs-vite-2026.webp"
title: "Rollup vs Vite 2026: When You Need a Dedicated Bundler"
description: "Vite uses Rollup under the hood for production builds. When should you use Rollup directly instead of Vite? Compare use cases, configuration, and tradeoffs."
date: "2026-03-08"
authors: ["team"]
tier: 1
tags: ["rollup", "vite", "bundlers", "libraries", "comparison", "2026"]
---

## TL;DR

**Vite for apps, Rollup for libraries — and Vite uses Rollup internally anyway.** Vite (~18M weekly downloads) is the default for web applications in 2026. Rollup (~15M downloads) remains the best choice for building JavaScript/TypeScript libraries that will be published to npm. The key distinction: Vite wraps Rollup with a development server, HMR, and framework plugins that you simply do not need when building a library destined for npm. For app development, reach for Vite. For library authoring with precise output control, reach for Rollup.

## Key Takeaways

- **Vite uses Rollup for production builds** — they share the same output quality
- **Rollup produces the cleanest library bundles** — best tree-shaking in the ecosystem
- **Vite is better for applications** — dev server, HMR, plugin ecosystem for frameworks
- **Vite also has a library mode** (`build.lib`) — but bare Rollup gives more output control
- **Rollup plugin ecosystem** is fully available in Vite (backward compatible)
- **tsup** is the modern shortcut — wraps esbuild but produces Rollup-quality output for 90% of library use cases

---

## The Relationship Between Rollup and Vite

Vite is not a competitor to Rollup. It is built on top of Rollup:

```
Vite architecture:
  ┌─────────────────────────────────────┐
  │ Vite                                │
  │  ├── Dev server (native ESM)        │
  │  ├── esbuild (transpile + dep prep) │
  │  └── Rollup (production builds) ←──┼── This IS Rollup
  └─────────────────────────────────────┘
```

When you run `vite build`, you are running Rollup with Vite's plugin transform layer on top. The output quality is identical to running Rollup directly. This means choosing between them is not about output quality — it is about what else you need around the build step.

For an application, you want Vite because you get hot module replacement during development, CSS handling, image optimization, and a plugin ecosystem tuned for React, Vue, Svelte, and other frameworks.

For a library, you want Rollup (or a Rollup-based tool) because you only care about the production artifact. There is no dev server, no browser, no HMR — just an input file and a set of output formats.

---

## Why Use Rollup Directly for Library Authoring

When you publish a package to npm, your consumers will use Vite, webpack, or some other bundler to consume your package. What matters to them:

1. An ESM output (`dist/index.js`) for tree-shaking
2. A CJS output (`dist/index.cjs`) for Node.js compatibility
3. A UMD output if you need CDN usage via `<script>` tags
4. Type declarations (`dist/index.d.ts`)
5. `sideEffects: false` in `package.json` for aggressive tree-shaking

Rollup handles all of these with full control:

```javascript
// rollup.config.js — for a npm library
import typescript from '@rollup/plugin-typescript';
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import { dts } from 'rollup-plugin-dts';

export default [
  // Build the JavaScript
  {
    input: 'src/index.ts',
    output: [
      {
        file: 'dist/index.cjs',
        format: 'cjs',          // CommonJS for Node.js
        exports: 'named',
      },
      {
        file: 'dist/index.js',
        format: 'esm',          // ES modules for modern bundlers
        exports: 'named',
        sourcemap: true,
      },
      {
        file: 'dist/index.umd.js',
        format: 'umd',          // UMD for CDN / <script> usage
        name: 'MyLibrary',
        globals: {
          react: 'React',
          'react-dom': 'ReactDOM',
        },
      },
    ],
    plugins: [
      resolve(),
      commonjs(),
      typescript({ tsconfig: './tsconfig.build.json' }),
    ],
    external: ['react', 'react-dom'], // Never bundle peer deps
  },
  // Build the type definitions
  {
    input: 'src/index.ts',
    output: { file: 'dist/index.d.ts', format: 'esm' },
    plugins: [dts()],
  },
];
```

This produces exactly:
- `dist/index.js` — ES module for Vite/webpack tree-shaking
- `dist/index.cjs` — CommonJS for older Node.js
- `dist/index.umd.js` — UMD for CDN usage
- `dist/index.d.ts` — TypeScript types

Pair this with a proper `package.json` exports field:

```json
{
  "exports": {
    ".": {
      "import": "./dist/index.js",
      "require": "./dist/index.cjs",
      "types": "./dist/index.d.ts"
    }
  },
  "sideEffects": false
}
```

---

## Vite's Library Mode

Vite does have a library mode via `build.lib` that handles many of the same cases:

```javascript
// vite.config.ts — library mode
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import dts from 'vite-plugin-dts';

export default defineConfig({
  plugins: [
    react(),
    dts({ insertTypesEntry: true }),
  ],
  build: {
    lib: {
      entry: 'src/index.ts',
      name: 'MyLibrary',
      formats: ['es', 'cjs', 'umd'],
      fileName: (format) => `index.${format}.js`,
    },
    rollupOptions: {
      external: ['react', 'react-dom'],
      output: {
        globals: {
          react: 'React',
          'react-dom': 'ReactDOM',
        },
      },
    },
  },
});
```

So when should you choose bare Rollup over Vite's library mode? The main scenarios:

- **Complex multi-entry libraries** — Rollup handles multiple entry points and chunk splitting with more precision
- **Custom code transformations** — Rollup's plugin API is more granular for AST-level transforms
- **Avoiding framework dependencies** — Vite's library mode still pulls in Vite's own dependencies; bare Rollup keeps your build toolchain lean
- **Fine-grained `external` control** — Rollup's `external` option accepts functions, RegExp patterns, and per-output-format configuration

---

## Bundle Analysis

Both ecosystems have visualization tools to understand what is in your bundle:

```bash
# Rollup: rollup-plugin-visualizer
npm install --save-dev rollup-plugin-visualizer
```

```javascript
// rollup.config.js
import { visualizer } from 'rollup-plugin-visualizer';

export default {
  plugins: [
    visualizer({
      open: true,        // Opens browser automatically
      filename: 'stats.html',
      gzipSize: true,
      brotliSize: true,
    }),
  ],
};
```

```bash
# Vite: rollup-plugin-visualizer works here too
npm install --save-dev rollup-plugin-visualizer
```

```javascript
// vite.config.ts
import { visualizer } from 'rollup-plugin-visualizer';

export default defineConfig({
  plugins: [
    visualizer({
      open: true,
      filename: 'dist/stats.html',
    }),
  ],
});
```

Because Vite uses Rollup internally, the same `rollup-plugin-visualizer` works in both. There is also `vite-bundle-visualizer` (a thin wrapper) and `rollup-plugin-bundle-stats` for CI integration.

---

## Tree-Shaking

Rollup pioneered tree-shaking in the JavaScript bundler ecosystem. Its tree-shaking is still considered the gold standard:

```javascript
// Your library exports three things
export function add(a: number, b: number) { return a + b; }
export function multiply(a: number, b: number) { return a * b; }
export const VERSION = '1.0.0';

// Consumer imports only add
import { add } from 'your-library';

// Rollup output — multiply and VERSION are completely eliminated
// webpack output — depends on sideEffects field; can include unreferenced exports
// esbuild output — similar quality to Rollup for simple cases
```

For libraries where consumer bundle size matters, Rollup's tree-shaking is worth using directly or through tsup. The difference is most visible with larger libraries where eliminating unused exports measurably reduces the consumer's bundle.

---

## tsup: The Modern Library Build Tool

For most library authors in 2026, `tsup` handles the 90% case without requiring a hand-crafted Rollup config:

```javascript
// tsup.config.ts — replaces custom Rollup config for most libraries
import { defineConfig } from 'tsup';

export default defineConfig({
  entry: ['src/index.ts'],
  format: ['cjs', 'esm'],       // Both output formats
  dts: true,                     // Generate .d.ts files
  splitting: false,
  sourcemap: true,
  clean: true,
  minify: false,                 // Libraries usually skip minification
  external: ['react'],           // Peer dependencies
  treeshake: true,
});
```

tsup uses esbuild internally (not Rollup), but produces comparable output. The tradeoff: faster build times, slightly less control. For complex multi-output libraries or those needing Rollup-specific plugins, bare Rollup is still the better tool.

---

## Package Health

| Package | Weekly Downloads | Size (gzip) | Latest Version | Active |
|---------|-----------------|-------------|----------------|--------|
| rollup | ~15M | ~1.5MB install | 4.x | Yes |
| vite | ~18M | ~4MB install | 6.x | Yes |
| tsup | ~5M | ~2MB install | 8.x | Yes |
| esbuild | ~30M | ~10MB install | 0.24.x | Yes |

Both Rollup and Vite are actively maintained. Vite is backed by the Vue team and has the higher download count due to application usage. Rollup is the more foundational tool and sees steady growth as library authoring continues to grow. Neither is at risk of abandonment.

---

## Configuration Complexity

| Task | Rollup | Vite lib mode | tsup |
|------|--------|--------------|------|
| Single output format | Medium | Low | Minimal |
| ESM + CJS + UMD + types | High | Medium | Minimal |
| Framework app | Not ideal | Low | Not needed |
| Multi-entry library | High | Medium | Low |
| Custom AST transforms | High (plugins) | Medium (plugins) | Low |

---

## When to Choose Each

**Use Vite when:**
- Building a web application (React, Vue, Svelte, vanilla)
- You need a dev server with HMR during development
- You want framework-specific plugins (React Fast Refresh, Vue SFC, Svelte HMR)
- You are setting up a new project and want sensible defaults

**Use Rollup directly when:**
- Building a library with unusual multi-format output requirements
- You need precise control over what gets bundled and what stays external
- You are writing custom build plugins that need deep Rollup API access
- You need UMD output with specific global variable names for CDN usage

**Use tsup when:**
- Building a TypeScript npm library (the modern default for most cases)
- You want Rollup-quality tree-shaking without the configuration overhead
- You are building a CLI tool or Node.js package

---

## Related Resources

The relationship between Rollup and Vite is evolving. Vite uses Rollup for production builds today, but the Vite team has been exploring a Rust-based bundler (Rolldown) that would replace the Rollup production build path while maintaining Rollup plugin API compatibility. When Rolldown becomes Vite's default bundler, the performance gap for production builds will narrow significantly — Vite will gain faster production builds while Rollup retains its plugin ecosystem dominance and direct API access.

For library authors currently on Rollup directly, tsup has become the practical default for TypeScript packages: it wraps esbuild for the actual compilation, delegates tree-shaking to esbuild's Rollup-compatible algorithm, and generates CJS/ESM dual output with TypeScript declarations in one configuration file. The only reason to use Rollup directly over tsup is if you need Rollup-specific plugin behavior or unusual output formats that tsup doesn't expose in its configuration surface. For the large majority of TypeScript library authors, tsup provides the right tradeoff: Rollup-quality output with a fraction of the configuration effort required to set up Rollup from scratch, and a maintained preset that handles the CJS/ESM dual-output problem without manual entry point configuration.

The `preserveModules` option in Rollup is worth knowing for library authors who need to maintain file-per-file ESM output rather than a single bundled file. When set to `true`, Rollup outputs the same directory structure as the source, preserving individual module boundaries. This is the correct approach for component libraries (like shadcn/ui itself, if it were a traditional package) where consumers want to import individual components without dragging in the entire library: `import { Button } from 'my-ui/button'` instead of `import { Button } from 'my-ui'`. Vite's library mode does not expose `preserveModules` directly in its `build.lib` configuration — you must pass it through `build.rollupOptions.output.preserveModules`. This is another reason library authors sometimes prefer bare Rollup: the full output configuration API is directly accessible without searching for which Vite options proxy down to which Rollup options.

One configuration detail that trips up many library authors switching from Vite's library mode to bare Rollup is the `external` option. Vite's `rollupOptions.external` only applies to the Rollup production build path; some Vite plugins handle peer dependencies differently during development versus production, leading to subtle bundling differences between `vite serve` and `vite build`. Bare Rollup's `external` option is authoritative across the entire build — it accepts strings, RegExp, or a function `(id) => boolean` — giving you precise control over what ends up in the bundle. For libraries with complex peer dependency trees (a React component library that also optionally depends on `react-query` and `zustand`), Rollup's `external` function form lets you exclude all peer packages with `(id) => !id.startsWith('.')` while including only your vendored utilities. This level of control is the primary reason experienced library authors reach for bare Rollup over Vite's library mode when output composition matters.

- Compare Rollup and Vite package health: [/compare/rollup-vs-vite](/compare/rollup-vs-vite)
- How Rspack compares to the webpack/Rollup model: [/blog/rspack-vs-webpack-2026](/guides/rspack-vs-webpack-2026)
- Vite package details and download trends: [/packages/vite](/packages/vite)
