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

# Release management

This chapter introduces npm package version management and release practices for Rslib projects.

## Configure package.json

Before publishing an npm package, first complete its basic `package.json` configuration. This includes confirming the package `name` and initial `version`, and configuring its exports, runtime requirements, and publishing scope. For example, an ESM package built with Rslib can use the following configuration:

```json title="package.json"
{
  "name": "@example/lib",
  "version": "0.0.0",
  "type": "module",
  "exports": {
    ".": {
      "types": "./dist/index.d.ts",
      "default": "./dist/index.js"
    }
  },
  "types": "./dist/index.d.ts",
  "files": ["dist"],
  "engines": {
    "node": ">=22.19.0"
  },
  "publishConfig": {
    "access": "public",
    "registry": "https://registry.npmjs.org/"
  }
}
```

Pay particular attention to the following fields:

| Field                                                                         | Description                                                                                                                                                                                                                                                                                       |
| ----------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `exports`, `types`                                                            | Point the exports and type declarations to the actual build artifacts generated by Rslib.                                                                                                                                                                                                         |
| `files`                                                                       | Explicitly list the files to publish to avoid accidentally publishing tests, configuration, and other unrelated content.                                                                                                                                                                          |
| `engines.node`                                                                | Declare the minimum supported Node.js version.                                                                                                                                                                                                                                                    |
| `publishConfig`                                                               | Scoped packages can set `access: "public"` for public publishing. This field can also override the registry used when publishing.                                                                                                                                                                 |
| `dependencies`, `optionalDependencies`, `peerDependencies`, `devDependencies` | Rslib applies default external rules to third-party dependencies based on these fields. Declare dependencies according to their actual purpose; see [Default handling of third-party dependencies](/guide/advanced/third-party-deps.md#default-handling-of-third-party-dependencies) for details. |
| `sideEffects`                                                                 | Declare package side effects correctly, including files that have import side effects such as CSS, polyfills, and global registrations.                                                                                                                                                           |

Also make sure that the package does not set `private: true`. It is also recommended to add `description`, `license`, and `repository` so users can understand and locate the project on npm.

## pnpm version management

pnpm provides [versioning and publishing features](https://pnpm.io/versioning) for recording changes, updating package versions, generating changelogs, synchronizing dependency versions between workspace packages, and publishing npm packages.

:::tip pnpm version requirement

These versioning features require pnpm v11.13.0 or later. We recommend pinning the pnpm version with `packageManager` and declaring the minimum version with `engines.pnpm`:

```json title="package.json"
{
  "packageManager": "pnpm@12.4.1",
  "engines": {
    "pnpm": ">=11.13.0"
  }
}
```

:::

The common versioning and publishing commands can be run locally or integrated into GitHub Actions and other CI platforms:

| Command                                          | Stage       | Purpose                                                                   |
| ------------------------------------------------ | ----------- | ------------------------------------------------------------------------- |
| [pnpm change](https://pnpm.io/cli/change)        | Development | Record affected packages, version bump levels, and changes.               |
| [pnpm change status](https://pnpm.io/cli/change) | Preparation | View pending change records and their version changes.                    |
| [pnpm version](https://pnpm.io/cli/version)      | Preparation | Update package versions, including multiple workspace packages with `-r`. |
| [pnpm lane](https://pnpm.io/cli/lane)            | Preparation | Manage prerelease channels such as Alpha, Beta, and RC.                   |
| [pnpm publish](https://pnpm.io/cli/publish)      | Publishing  | Publish packages directly to npm.                                         |
| [pnpm stage publish](https://pnpm.io/cli/stage)  | Publishing  | Stage packages on npm for review and approval before release.             |

You can configure pnpm versioning behavior in `pnpm-workspace.yaml`. For example, configure a fixed version group to keep multiple packages at the same version:

```yaml title="pnpm-workspace.yaml"
versioning:
  fixed:
    - ['@example/*']
```

See the [pnpm versioning configuration](https://pnpm.io/settings/versioning) for all available options.

## Release workflow

A complete pnpm-based release process includes the following steps:

1. [Record changes](#record-changes)
2. [Update versions](#update-versions)
3. [Maintain changelog](#maintain-changelog)
4. [Build and validate](#build-and-validate)
5. [Publish to npm](#publish-to-npm)

### Record changes

After completing changes that need to be released, run [pnpm change](https://pnpm.io/cli/change) to record the affected packages, version bump level, and change summary:

```bash
pnpm change
```

pnpm generates a change record in the `.changeset/` directory based on the interactive options. The summary is used to generate the changelog during release, so it should clearly describe the user-facing behavior change. Commit the generated change record file together with the code.

You can also record changes non-interactively by specifying the package name and options such as `--bump` and `--summary`:

```bash
pnpm change --bump patch --summary "Example change" @example/core
```

Before preparing a release, view pending change records and their corresponding version changes:

```bash
pnpm change status
```

Single-package repositories can skip this step when change intents are not needed and specify the version type directly when updating versions.

### Update versions

Run [pnpm version](https://pnpm.io/cli/version) to update versions when preparing a release:

```bash
# Single-package repository
pnpm version patch

# monorepo
pnpm version -r
```

When run in a Git repository, regular `pnpm version` creates a Git commit and an annotated tag for the version change. A single-package repository can inspect the generated commit and tag, then push them to the main branch for publishing.

If you want to wrap single-package version updates in a script, add the following to `package.json`:

```json title="package.json"
{
  "scripts": {
    "bump": "pnpm version -m \"release: v%s\""
  }
}
```

In a monorepo project, run `pnpm version -r`. Recursive mode applies the change records and updates package versions, workspace dependencies, and changelogs, but does not create a commit or tag because one run may produce different versions for multiple packages. After checking the generated files, commit and push these changes to an agreed release branch, such as `release/v1.2.3`, and create a PR. Publish from that branch first, then merge the PR after the release is verified.

During the version update process, choose an appropriate version type based on your needs.

#### Stable and prerelease versions

Stable versions are intended for all users. They do not include a prerelease identifier and normally use the `latest` dist-tag.

Alpha, Beta, and RC versions are installable test versions released before a stable version. Use an npm dist-tag that matches the version suffix so that prereleases do not affect the default installation:

| Version         | npm dist-tag |
| --------------- | ------------ |
| `1.0.0-alpha.0` | `alpha`      |
| `1.0.0-beta.0`  | `beta`       |
| `1.0.0-rc.0`    | `rc`         |
| `1.0.0`         | `latest`     |

You can create a prerelease with [pnpm version](https://pnpm.io/cli/version):

```bash
pnpm version prerelease --preid beta
```

If a group of workspace packages needs continuous prerelease releases, use [pnpm lane](https://pnpm.io/cli/lane) to maintain an independent prerelease channel:

```bash
pnpm lane beta --filter '@example/*'
pnpm version -r

# Move back to the main lane before releasing a stable version
pnpm lane main --filter '@example/*'
pnpm version -r
```

:::note

Do not publish prereleases to `latest`, otherwise users installing the package normally may receive an unstable version.

:::

#### Snapshot packages

Snapshot packages help validate a PR, branch, or commit without changing the stable version or changelog. For local validation, build and pack the package, then install the generated archive in a consumer project:

```bash
# Run in the library project
pnpm build
pnpm pack

# Run in the consumer project
pnpm add /path/to/package.tgz
```

To provide collaborators with an installable Snapshot package in a PR, use [pkg-pr-new](https://github.com/stackblitz-labs/pkg.pr.new#readme). It publishes packages to a separate npm-compatible service rather than the npm registry, so it does not increase the number of npm package versions or modify package metadata such as dist-tags.

### Maintain changelog

When you run `pnpm version -r`, pnpm generates changelogs from the summaries recorded by `pnpm change`. To maintain a `CHANGELOG.md` for each package in the repository, set [versioning.changelog.storage](https://pnpm.io/settings/versioning#versioningchangelogstorage) to `repository`:

```yaml title="pnpm-workspace.yaml"
versioning:
  changelog:
    storage: repository
```

If the project uses GitHub release notes as the user-facing version record, you do not need to maintain an additional `CHANGELOG.md` in the repository. GitHub supports [automatically generated release notes](https://docs.github.com/repositories/releasing-projects-on-github/automatically-generated-release-notes), and you can add release highlights, migration instructions, and important notes to the generated content.

### Build and validate

After determining the version to publish, use the corresponding commit locally or in CI, install dependencies, and build:

```bash
pnpm install --frozen-lockfile
pnpm build
```

Before publishing, run [pnpm publish --dry-run](https://pnpm.io/cli/publish) to check the files and package information that will be published:

```bash
# Single-package repository
pnpm publish --dry-run

# monorepo
pnpm --filter './packages/*' -r publish --dry-run
```

You can also check the package structure, exports, and type declarations to ensure that the final npm package can be resolved and installed correctly. Rslib supports the following Rsbuild plugins for these checks:

- [rsbuild-plugin-publint](https://github.com/rstackjs/rsbuild-plugin-publint): Checks common issues in `package.json`, package structure, and exports.
- [rsbuild-plugin-arethetypeswrong](https://github.com/rstackjs/rsbuild-plugin-arethetypeswrong): Checks whether type declarations work correctly with different module resolution strategies.

Install the plugins first, then add them to the `plugins` configuration. The plugins check release artifacts after the build completes.


```sh [npm]
npm add rsbuild-plugin-publint rsbuild-plugin-arethetypeswrong -D
```

```sh [yarn]
yarn add rsbuild-plugin-publint rsbuild-plugin-arethetypeswrong -D
```

```sh [pnpm]
pnpm add rsbuild-plugin-publint rsbuild-plugin-arethetypeswrong -D
```

```sh [bun]
bun add rsbuild-plugin-publint rsbuild-plugin-arethetypeswrong -D
```

```sh [deno]
deno add npm:rsbuild-plugin-publint npm:rsbuild-plugin-arethetypeswrong -D
```

The following configuration enables the checks with the `CI` environment variable set by most CI platforms, avoiding an impact on local build workflows. The checks run automatically when packages are built during the release workflow:

```ts title="rslib.config.ts"
import { defineConfig } from '@rslib/core';
import { pluginAreTheTypesWrong } from 'rsbuild-plugin-arethetypeswrong';
import { pluginPublint } from 'rsbuild-plugin-publint';

export default defineConfig({
  dts: true,
  plugins: [
    pluginPublint({
      enable: Boolean(process.env.CI),
    }),
    pluginAreTheTypesWrong({
      enable: Boolean(process.env.CI),
    }),
  ],
});
```

You can also add syntax compatibility, bundle size, or installation tests based on the type of artifact.

### Publish to npm

There are two ways to publish npm packages:

- **Staged publishing (recommended):** [pnpm stage publish](https://pnpm.io/cli/stage) separates uploading a package from making it publicly available. Staged versions are not resolved or installed by package managers, so maintainers can inspect the package before approving it on the npm website or with [pnpm stage approve](https://pnpm.io/cli/stage). This approach can reduce supply-chain risks if an npm token is stolen or a CI environment is compromised.

  ```bash
  # Single-package repository
  pnpm stage publish --tag latest --no-git-checks

  # monorepo
  pnpm --filter './packages/*' -r stage publish --tag latest --no-git-checks
  ```

  Approve the staged packages on the npm website after checking them.

- **Direct publishing:** If manual approval is not required, use [pnpm publish](https://pnpm.io/cli/publish) directly:

  ```bash
  # Single-package repository
  pnpm publish --tag latest --no-git-checks

  # monorepo
  pnpm --filter './packages/*' -r publish --tag latest --no-git-checks
  ```

For prereleases, replace `latest` with the corresponding `alpha`, `beta`, or `rc` dist-tag.

## GitHub integration

You can use GitHub Actions to build and publish the npm package. We recommend using npm [Trusted publishing](https://docs.npmjs.com/trusted-publishers/) for OIDC authentication to avoid storing long-lived npm tokens in CI.

### Publish from a tag

For a simple single-package repository, after updating the version, push the commit containing the version change to the main branch, then push the corresponding Git tag. The release workflow runs for the `v*` tag and can also be triggered manually:

```yaml title=".github/workflows/release.yml"
name: Release

on:
  push:
    tags:
      - 'v*'

  workflow_dispatch:

permissions: {}

jobs:
  publish:
    runs-on: ubuntu-latest
    environment: npm
    permissions:
      contents: read
      id-token: write
    steps:
      - name: Checkout
        uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

      - name: Setup Node.js
        uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
        with:
          node-version: 24

      - name: Install pnpm
        uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0
        with:
          run_install: true

      - name: Build
        run: pnpm run build

      - name: Publish to npm
        run: pnpm stage publish --tag latest --no-git-checks
```

:::note

To publish an `alpha`, `beta`, or other prerelease version, replace `latest` with the corresponding npm dist-tag.

:::

### Publish from a release branch

For a monorepo that publishes multiple packages together, use the release workflow to select an agreed release branch. After you use **Run workflow** to select the branch and npm dist-tag, the workflow builds that branch and recursively stages the packages for publishing:

```yaml title=".github/workflows/release.yml"
name: Release

on:
  workflow_dispatch:
    inputs:
      npm_tag:
        type: choice
        description: 'Specify npm tag'
        required: true
        default: 'alpha'
        options:
          - alpha
          - beta
          - rc
          - latest
      branch:
        description: 'Branch to release'
        required: true
        default: 'main'

permissions: {}

jobs:
  release:
    runs-on: ubuntu-latest
    environment: npm
    permissions:
      contents: read
      id-token: write
    steps:
      - name: Checkout
        uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
        with:
          fetch-depth: 1
          ref: ${{ github.event.inputs.branch }}

      - name: Setup Node.js
        uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
        with:
          node-version: 24

      - name: Install pnpm
        uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0
        with:
          run_install: true

      - name: Build
        run: pnpm run build

      - name: Publish to npm
        run: |
          pnpm --filter './packages/*' -r stage publish --tag ${{ github.event.inputs.npm_tag }} --no-git-checks
```

> The top-level `permissions: {}` disables the default `GITHUB_TOKEN` permissions. The publishing job only grants `contents: read` to check out the source and `id-token: write` for npm OIDC authentication.

:::note

When configuring Trusted publishing on npm, the repository and workflow filename must match the workflow. If you also configure an Environment for Trusted publishing, use the same name as the `npm` Environment in the examples above.

:::
