This document describes the automated release process, continuous integration, and continuous deployment (CI/CD) infrastructure for React Router. It covers the four release channels (stable, prerelease, nightly, experimental), the Changesets-based version management system, GitHub Actions workflows, npm Trusted Publishing, and quality gates.
For information about contributing code changes, see Contributing Guidelines. For version history and migration information, see Changelog and Version History.
React Router maintains four distinct release channels, each serving different purposes and triggered by different mechanisms:
| Channel | Trigger | Version Format | Purpose |
|---|---|---|---|
| Stable | Push to release-next or release-v6 branch | 7.x.x | Production-ready releases with full testing |
| Prerelease | Changesets prerelease mode on release branches | 7.x.x-pre.x | Release candidates before stable |
| Nightly | Scheduled cron (daily at 7:00 UTC) | 0.0.0-nightly-{sha}-{date} | Automated daily builds from dev branch |
| Experimental | Manual workflow_dispatch | 0.0.0-experimental-{sha} | Feature branch testing and early access |
Sources: .github/workflows/release.yml17-32 .github/workflows/release.yml140-260
React Router uses Changesets for version management and changelog generation. The process is fully automated through GitHub Actions.
Diagram: Changesets-driven release process from changeset files to npm publication
The workflow is defined in .github/workflows/release.yml41-88 and consists of three primary jobs:
release job: Runs the Changesets action which either creates a version PR or publishes to npmfind_package_version job: Extracts the published version of react-router from the outputcomment job: Uses remix-run/release-comment-action to notify related issues and PRsSources: .github/workflows/release.yml41-139 package.json17-18 package.json31-33
Developers create changeset files in the .changeset/ directory using:
Each changeset file specifies:
When the version PR is merged, Changesets automatically:
package.json versions across all affected packagesSources: package.json30 .github/workflows/release.yml80-84
The CI/CD infrastructure consists of multiple GitHub Actions workflows that run on different triggers and provide different levels of testing coverage.
Diagram: Complete CI/CD workflow architecture showing all GitHub Actions workflows and their triggers
Sources: .github/workflows/test.yml1-71 .github/workflows/integration-pr-ubuntu.yml1-36 .github/workflows/integration-pr-windows-macos.yml1-55 .github/workflows/integration-full.yml1-55 .github/workflows/release.yml1-260
The primary test workflow runs on every push to main/dev branches and pull requests. It executes in parallel on Node.js 20.18 and 22:
Test stages:
pnpm typecheck validates TypeScript across all packagespnpm lint runs ESLint with project-specific rulespnpm test executes Jest test suitesThe workflow uses pnpm workspaces to install dependencies efficiently with --frozen-lockfile to ensure reproducible builds.
Sources: .github/workflows/test.yml22-71 package.json15-24
Integration tests use Playwright and run across multiple operating systems, Node versions, and browsers. The test matrix adapts based on what code is changed:
| Trigger | OS | Node | Browsers | Workflow |
|---|---|---|---|---|
| PR (base) | Ubuntu | 22 | Chromium | integration-pr-ubuntu.yml |
| PR (full) | Ubuntu, Windows, macOS | 20.18, 22 | Chromium, Firefox, Edge, WebKit | integration-pr-windows-macos.yml |
| Branch push | Ubuntu, Windows, macOS | 20.18, 22 | Chromium, Firefox, Edge, WebKit | integration-full.yml |
PRs that touch @react-router/dev or pnpm-lock.yaml automatically trigger the full test matrix to catch platform-specific issues.
Diagram: Integration test infrastructure showing Playwright configuration and test matrix
Sources: .github/workflows/shared-integration.yml1-70 .github/workflows/integration-pr-ubuntu.yml28-35 .github/workflows/integration-pr-windows-macos.yml19-54 package.json23-29
React Router publishes to npm using Trusted Publishing, which eliminates the need to store npm tokens as GitHub secrets. This is configured through npm's OpenID Connect (OIDC) integration with GitHub Actions.
The publishing process requires:
id-token: write permission to generate OIDC tokensAll release jobs specify these requirements:
Sources: .github/workflows/release.yml48-51 .github/workflows/release.yml64 .github/workflows/release.yml171 .github/workflows/release.yml239
Diagram: npm Trusted Publishing flow showing OIDC token generation and verification
The actual publish script is at package.json32 and runs node scripts/publish.js, which handles the multi-package publication process across the monorepo.
Sources: .github/workflows/release.yml1-4 .github/workflows/release.yml213-215 .github/workflows/release.yml257-259 package.json32
Nightly releases run automatically via cron at 0 7 * * * (7:00 AM UTC daily). The workflow:
dev branch (not main)0.0.0-nightly-{shortSHA}-{yyyyMMdd}pnpm run version@nightly tagVersion collision prevention: The workflow checks if the latest nightly tag matches the current commit SHA, skipping the release if it does. This prevents duplicate releases when no changes have been made.
Sources: .github/workflows/release.yml146-216 .github/workflows/release.yml177-198 package.json33
Experimental releases are manually triggered via workflow_dispatch and accept a branch name as input. They:
0.0.0-experimental-{shortSHA}experimental/{version}This allows testing of feature branches and early access to experimental APIs.
Sources: .github/workflows/release.yml217-260 .github/workflows/release.yml28-31
Documentation is automatically generated and committed back to the repository on pushes to main and dev branches.
The docs.yml workflow generates two types of documentation:
Diagram: Documentation generation workflow producing both TypeDoc HTML and JSDoc markdown
TypeDoc generates HTML API reference documentation from TypeScript declarations. The output is written to the public/ directory and includes full type information for all exported APIs.
Configuration is managed in typedoc.json and the command is defined at package.json11
The custom JSDoc parser at scripts/docs.ts extracts structured documentation from JSDoc comments in source files. It:
dox library@public, @category, @mode, @param, @returns tags{@link} references to other APIs using typedoc outputThe generated markdown is committed to docs/api/ for use in the documentation site.
Sources: .github/workflows/docs.yml1-68 package.json10-12 scripts/docs.ts1-850 scripts/docs.ts169-175 scripts/docs.ts360-382
Before any release (stable, nightly, or experimental), the following quality gates must pass:
pnpm build must complete successfully for all packagespnpm typecheck must passpnpm test must passSources: .github/workflows/test.yml60-70 package.json15-24 .eslintrc1-96
The format.yml workflow automatically formats code on pushes to main and dev:
contributors.yml file alphabeticallypnpm formatThis ensures consistent code style without requiring manual intervention.
Sources: .github/workflows/format.yml1-55 package.json13-14
The deduplicate-lock-file.yml workflow runs when pnpm-lock.yaml is updated on the dev branch. It:
pnpm dedupe to remove duplicate dependenciesThis keeps the dependency tree minimal and reduces bundle sizes.
Sources: .github/workflows/deduplicate-lock-file.yml1-50
React Router uses pnpm workspaces with wireit for incremental builds. The build process:
pnpm install --frozen-lockfilepnpm build which triggers wireit-based buildspackage.json with wireit configurationExample from react-router package:
The tsup bundler is used for most packages, producing both CommonJS and ESM outputs. The React Router core package also builds React Server Component variants using a separate config.
Sources: packages/react-router/package.json106-125 package.json5-6 .github/workflows/test.yml60-61
Each package defines complex exports fields to support different module systems and environments:
react-server condition for RSC.d.ts and .d.mts declaration filesSources: packages/react-router/package.json24-104 packages/react-router-dom/package.json25-41
After successful publication, the comment job notifies users by posting comments on related issues and pull requests using remix-run/[email protected].
The action:
"awaiting release" label"🗺 Roadmap" label openThis provides automatic closure and notification for fixed issues without manual intervention.
Sources: .github/workflows/release.yml117-139 .github/workflows/release.yml132-138
The repository defines several key scripts for release management:
| Script | Command | Purpose |
|---|---|---|
build | pnpm run --filter="./packages/**/*" build | Build all packages in monorepo |
test | jest | Run unit test suites |
test:integration | pnpm build && pnpm test:integration:run | Build and run Playwright tests |
prerelease | pnpm build | Pre-release build hook |
release | changeset publish | Publish packages to npm |
changeset | changeset | Interactive changeset creation |
changeset:version | changeset version && node ./scripts/remove-prerelease-changelogs.mjs | Version bump with changelog cleanup |
version | node ./scripts/version | Custom version script for nightly/experimental |
publish | node scripts/publish.js | Multi-package publish script |
Sources: package.json4-34
React Router's release and CI/CD infrastructure provides:
The entire process is orchestrated through GitHub Actions workflows defined in .github/workflows/ with minimal manual intervention required for stable releases.
Refresh this wiki