> For AI agents: the complete documentation index is available at /llms.txt, the full documentation bundle is available at /llms-full.txt.

# Output format

There are multiple supported output formats for the generated JavaScript files in Rslib: [ESM](#esm--cjs), [CJS](#esm--cjs), [UMD](#umd), [MF](#mf), and [IIFE](#iife). In this chapter, we will introduce the differences between these formats and how to choose the right one for your library.

## ESM / CJS

Library authors need to carefully consider which module formats to support. Let's understand ESM (ECMAScript Modules) and CJS (CommonJS) and when to use them.

### What are ESM and CJS?

- **ESM**: <ESM />

- **CommonJS**: <CJS />

::: tip

Read the [Node.js Package Configuration Guide](https://nodejs.github.io/package-examples/) to learn more about ESM and CJS, including file structure, `package.json` configuration, module interoperability, and best practices.

:::

### Choose module formats

The choice of module format usually depends on how the package will be consumed. For new packages, prefer pure ESM and add a dual ESM/CJS build only when there is a clear compatibility requirement.

#### Prefer pure ESM

ESM is the standard JavaScript module format. It is supported by modern browsers, Node.js, and mainstream build tools, and enables static analysis and tree shaking. Compared with CommonJS, `import` and `export` statements are more concise and easier to read. Additionally, maintaining one format reduces build configuration, package exports, and test combinations.

If consumers still use CommonJS and `package.json#exports` allows `require()` to resolve the ESM entry, they can load a pure ESM package directly with `require()` on [Node.js `^20.19.0` or `>=22.12.0`](https://nodejs.org/api/modules.html#loading-ecmascript-modules-using-require), provided that neither the entry nor its dependencies use top-level `await`. Library authors do not need to publish a separate CJS output only for these consumers:

```js
const packageExports = require('pure-esm-package');
```

#### Publish dual ESM/CJS for compatibility

Consider publishing both ESM and CJS when:

- CommonJS consumers use Node.js versions, tools, or runtimes that cannot load ESM synchronously with `require()`.
- Consumers explicitly require a separate CJS file.

Dual formats provide broader compatibility and help consumers migrate gradually to ESM, but require separate builds, export mappings, and tests. Loading both formats can also create separate instances of the same package, leading to inconsistent state or identity checks. Confirm that target consumers need CJS before adding it.

## UMD

### What is UMD?

UMD stands for [Universal Module Definition](https://github.com/umdjs/umd), a pattern for writing JavaScript modules that can work universally across different environments, such as both the browser and Node.js. Its primary goal is to ensure compatibility with the most popular module systems, including AMD (Asynchronous Module Definition), CommonJS (CJS), and browser globals.

### When to use UMD?

If you are building a library that needs to be used in both the browser and Node.js environments, UMD is a good choice. UMD can be used as a standalone script tag in the browser or as a CommonJS module in Node.js.

A detailed answer from StackOverflow: [What is the Universal Module Definition (UMD)?](https://stackoverflow.com/a/77284527/8063488)

> However, for frontend libraries, you still offer a single file for convenience, that users can download (from a CDN) and directly embed in their web pages. This still commonly employs a UMD pattern, it's just no longer written/copied by the library author into their source code, but added automatically by the transpiler/bundler.
>
> And similarly, for backend/universal libraries that are supposed to work in
> Node.js, you still also distribute a commonjs module build via npm to support
> all the users who still use a legacy version of Node.js (and don't want/need
> to employ a transpiler themselves). This is less common nowadays for new
> libraries, but existing ones try hard to stay backwards-compatible and not
> cause applications to break.

### How to build a UMD library?

- Set the [lib.format](/config/lib/format.md) to `umd` in the Rslib configuration file.
- If the library need to be exported with a name, set [lib.umdName](/config/lib/umd-name.md) to the name of the UMD library.
- Use [output.externals](/config/rsbuild/output.md#outputexternals) to specify the external dependencies that the UMD library depends on, [lib.autoExtension](/config/lib/auto-extension.md) is enabled by default for UMD.

### Examples

The following Rslib config is an example to build a UMD library.

- `lib.format: 'umd'`: instruct Rslib to build in UMD format.
- `lib.umdName: 'RslibUmdExample'`: set the export name of the UMD library.
- `output.externals.react: 'React'`: specify the external dependency `react` could be accessed by `window.React`.
- `runtime: 'classic'`: use the classic runtime of React to support applications that using React version under 18.

```ts title="rslib.config.ts"
import { pluginReact } from '@rsbuild/plugin-react';
import { defineConfig } from '@rslib/core';

export default defineConfig({
  lib: [
    {
      // [!code highlight:6]
      format: 'umd',
      umdName: 'RslibUmdExample',
      output: {
        externals: {
          react: 'React',
        },
        distPath: './dist/umd',
      },
    },
  ],
  output: {
    target: 'web',
  },
  plugins: [
    pluginReact({
      swcReactOptions: {
        runtime: 'classic', // [!code highlight]
      },
    }),
  ],
});
```

## MF

### What is MF?

MF stands for Module Federation. Module Federation is an architectural pattern for JavaScript application decomposition (similar to microservices on the server-side), allowing you to share code and resources between multiple JavaScript applications (or micro-frontends).

See [Module Federation](https://rsbuild.rs/guide/advanced/module-federation) for more details.

## IIFE


The iife format stands for "immediately-invoked function expression" and is intended to be run in the browser. Wrapping your code in a function expression ensures that any variables in your code don't accidentally conflict with variables in the global scope. If your entry point has exports that you want to expose as a global in the browser, you can configure that global's name using the global name setting.

In IIFE format, [output.globalObject](https://rspack.rs/config/output#outputglobalobject) is set to [globalThis](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/globalThis) by default. The `import` statements that match [externals](/config/rsbuild/output.md#outputexternals) in the source code will be transformed to access properties through `globalThis`. You can override [output.globalObject](https://rspack.rs/config/output#outputglobalobject) to any value.

When specifying the `iife` format, the source code and corresponding output are as follows:

```js title="source code"
// parent-sdk is marked as externals
// externals: ['parent-sdk']
import { version } from 'parent-sdk';
alert(version);
```

```js title="IIFE output"
(
  () => {
    const external_parent_sdk_namespaceObject = globalThis['parent-sdk'];
    alert(external_parent_sdk_namespaceObject.version);
  },
)();
```
