Skip to content

Plugin API

Overview

Rolldown's plugin interface is almost fully compatible with Rollup's (detailed tracking here), so if you have written a Rollup plugin before, you already know how to write a Rolldown plugin!

A Rolldown plugin is an object that satisfies the plugin interface described below. A plugin should be distributed as a package which exports a function that can be called with plugin specific options and returns such an object.

Plugins allow you to customize Rolldown's behavior by, for example, transpiling code before bundling, or shimming a built-in module that is not available.

Example

The following example shows a Rolldown plugin that intercepts import requests to example-virtual-module and returns a custom content for it.

js
const id = 'example-virtual-module';
const resolvedId = '\0' + id;

export default function examplePlugin() {
  return {
    name: 'example-plugin', // this name will show up in logs and errors
    resolveId(source) {
      if (source === id) {
        // this signals to Rolldown that this import should resolve to a module named `\0example-virtual-module`
        return resolvedId;
      }
      return null; // other ids should be handled as usual
    },
    load(id) {
      if (id === resolvedId) {
        // the source code for `\0example-virtual-module`
        return `export default 'Hello from ${id}';`;
      }
      return null; // other ids should be handled as usual
    },
  };
}
js
import { defineConfig } from 'rolldown';
import examplePlugin from './rolldown-plugin-example.js';

export default defineConfig({
  plugins: [examplePlugin()],
});

Virtual Modules

This plugin implements a pattern which is commonly called "virtual modules". A virtual module is a module that does not exist on the file system and is instead resolved and provided by a plugin. In the example above, example-virtual-module is never read from disk because the plugin intercepts the import in resolveId and supplies the module’s source code in load. This pattern is useful for injecting helper functions.

Hook Filters

This example plugin does not use Hook Filters for simplicity. To improve performance, it is recommended to use them when possible.

Conventions

  • Plugins should have a clear name with rolldown-plugin- prefix.
  • Include rolldown-plugin keyword in the package.json keywords field.
  • Make sure your plugin outputs correct source mappings if appropriate.
  • If your plugin uses "virtual modules", prefix the module ID with \0. This prevents other plugins from trying to process it.
  • (recommended) Plugins should be tested.
  • (recommended) Plugins should be documented in English.

Plugin Interface

The Plugin interface has a required name property and multiple optional properties and hooks.

Hooks are methods defined on the plugin that can be used to interact with the build process. They are called at various stages of the build. Hooks can affect how a build is run, provide information about a build, or modify a build once complete. There are different kinds of hooks:

  • async: The hook may also return a Promise resolving to the same type of value; otherwise, the hook is marked as sync.
  • first: If several plugins implement this hook, the hooks are run sequentially until a hook returns a value other than null or undefined.
  • sequential: If several plugins implement this hook, all of them will be run in the specified plugin order. If a hook is async, subsequent hooks of this kind will wait until the current hook is resolved.
  • parallel: If several plugins implement this hook, all of them will be run in the specified plugin order. If a hook is async, subsequent hooks of this kind will be run in parallel and not wait for the current hook.

Instead of a method, hooks can also be objects with a handler property. In this case, the handler property is the actual hook method. This allows you to provide additional optional properties to control the behavior of the hook. See the ObjectHook type for more information.

There are two types of hooks: build hooks and output generation hooks.

Build Hooks

Build hooks are run during the build phase. They are mainly concerned with locating, providing and transforming input files before they are processed by Rolldown.

The first hook of the build phase is options, the last one is always buildEnd. If there is a build error, closeBundle will be called after that.

watchchangewatchChangeclosewatchercloseWatcheroptionsoptionsoutputoptionsoutputOptionsoptions->outputoptionsbuildstartbuildStartoutputoptions->buildstartresolveidresolveIdbuildstart->resolveideach entryloadloadresolveid->loadnon-externalbuildendbuildEndresolveid->buildendexternaltransformtransformload->transforminternaltransforminternalTransformtransform->internaltransformmoduleparsedmoduleParsedmoduleparsed->resolveideach importresolvedynamicimportresolveDynamicImportmoduleparsed->resolvedynamicimporteach import()moduleparsed->buildendno importsinternaltransform->moduleparsedresolvedynamicimport->resolveidunresolvedresolvedynamicimport->loadnon-externalresolvedynamicimport->buildendexternal
Legend
sequential
parallel
first
internal
sync
async
watchchangewatchChangeclosewatchercloseWatcheroptionsoptionsoutputoptionsoutputOptionsoptions->outputoptionsbuildstartbuildStartoutputoptions->buildstartresolveidresolveIdbuildstart->resolveideach entryloadloadresolveid->loadnon-externalbuildendbuildEndresolveid->buildendexternaltransformtransformload->transforminternaltransforminternalTransformtransform->internaltransformmoduleparsedmoduleParsedmoduleparsed->resolveideach importresolvedynamicimportresolveDynamicImportmoduleparsed->resolvedynamicimporteach import()moduleparsed->buildendno importsinternaltransform->moduleparsedresolvedynamicimport->resolveidunresolvedresolvedynamicimport->loadnon-externalresolvedynamicimport->buildendexternal
Legend
sequential
parallel
first
internal
sync
async

Note that internalTransform in the graph above is not a plugin hook, it is the step where Rolldown transforms non-JS code to JS.

Additionally, in watch mode the watchChange hook can be triggered at any time to notify a new run will be triggered once the current run has generated its outputs. Also, when watcher closes, the closeWatcher hook will be triggered.

Unsupported Hooks

The following Build Hooks are supported by Rollup, but not by Rolldown:

  • shouldTransformCachedModule (#4389)

Output Generation Hooks

Output generation hooks can provide information about a generated bundle and modify a build once complete. Plugins that only use output generation hooks can also be passed in via the output options and therefore run only for certain outputs.

The first hook of the output generation phase is renderStart, the last one is either generateBundle if the output was successfully generated via bundle.generate(...), writeBundle if the output was successfully generated via bundle.write(...), or renderError if an error occurred at any time during the output generation.

Additionally, closeBundle can be called as the very last hook, but it is the responsibility of the User to manually call bundle.close() to trigger this. The CLI will always make sure this is the case.

cluster_generatechunksrenderstartrenderStartbeforeaddonsrenderstart->beforeaddonseach chunkbannerbannerafteraddonsbanner->afteraddonsfooterfooterfooter->afteraddonsintrointrointro->afteraddonsoutrooutrooutro->afteraddonsrenderchunkrenderChunkminifyminifyrenderchunk->minifypostbannerpostBannerminify->postbannerpostfooterpostFooterminify->postfooteraugmentchunkhashaugmentChunkHashpostbanner->augmentchunkhashpostfooter->augmentchunkhashaugmentchunkhash->renderchunknext chunkgeneratebundlegenerateBundleaugmentchunkhash->generatebundlewritebundlewriteBundlegeneratebundle->writebundleclosebundlecloseBundlewritebundle->closebundlerendererrorrenderErrorrendererror->closebundlebeforeaddons->bannerbeforeaddons->footerbeforeaddons->introbeforeaddons->outroafteraddons->renderchunkeach chunkafteraddons->beforeaddonsnext chunk
Legend
sequential
parallel
first
internal
sync
async
cluster_generatechunksrenderstartrenderStartbeforeaddonsrenderstart->beforeaddonseach chunkbannerbannerafteraddonsbanner->afteraddonsfooterfooterfooter->afteraddonsintrointrointro->afteraddonsoutrooutrooutro->afteraddonsrenderchunkrenderChunkminifyminifyrenderchunk->minifypostbannerpostBannerminify->postbannerpostfooterpostFooterminify->postfooteraugmentchunkhashaugmentChunkHashpostbanner->augmentchunkhashpostfooter->augmentchunkhashaugmentchunkhash->renderchunknext chunkgeneratebundlegenerateBundleaugmentchunkhash->generatebundlewritebundlewriteBundlegeneratebundle->writebundleclosebundlecloseBundlewritebundle->closebundlerendererrorrenderErrorrendererror->closebundlebeforeaddons->bannerbeforeaddons->footerbeforeaddons->introbeforeaddons->outroafteraddons->renderchunkeach chunkafteraddons->beforeaddonsnext chunk
Legend
sequential
parallel
first
internal
sync
async

Note that minify in the graph above is not a plugin hook and is the step where Rolldown runs the minifier. Also note that postBanner and postFooter are not plugin hooks, these are output options and do not have corresponding hooks, unlike banner and footer.

Unsupported Hooks

The following Output Generation Hooks are supported by Rollup, but not by Rolldown:

  • resolveImportMeta (#1010)
  • resolveFileUrl
  • renderDynamicImport (#4532)

Plugin Context

A number of utility functions and informational bits can be accessed from within most hooks via this. See the PluginContext type for more information.

Notable Differences from Rollup

While Rolldown's plugin interface is largely compatible with Rollup's, there are some important behavioral differences to be aware of:

Output Generation Handling

In Rollup, all outputs are generated together in a single process. However, Rolldown handles each output generation separately. This means that if you have multiple output configurations, Rolldown will process each output independently, which can affect how certain plugins behave, especially those that maintain state across the entire build process.

These are the concrete differences:

  • outputOptions hook is called before the build hooks in Rolldown, whereas Rollup calls them after the build hooks
  • Build hooks are called for each output separately, whereas Rollup calls them once for all outputs
  • closeBundle hook is called only when you called generate() or write() at least once, whereas Rollup calls it regardless of whether you called generate() or write()

Sequential Hook Execution

In Rollup, certain hooks like writeBundle are "parallel" by default, meaning they run concurrently across multiple plugins. This requires plugins to explicitly set sequential: true if they need their hooks to run one after another.

In Rolldown, the writeBundle hook is already sequential by default, so plugins do not need to specify sequential: true for this hook.