Release Process
April 9, 2026 ยท View on GitHub
This document explains how to publish toolkit and React component releases from this repository. For release tag conventions and versioning context, see Release Versioning Strategy.
Overview
The design system distributes packages through GitHub Releases.
@ourfuturehealth/toolkitships an installable.tgzpackage and a compiled.zip@ourfuturehealth/react-componentsships an installable.tgzpackage- consumers install the package tarball URL, not a git subdirectory
Prerequisites
- ensure your branch is up to date with
main - all tests pass locally:
pnpm test - all linting passes locally:
pnpm lint - changelog and migration docs are updated when required
Release Steps
1. Decide what to release
Toolkit only:
- changes affect toolkit Sass, JavaScript, templates, or compiled assets
- bump
packages/toolkit/package.json
React only:
- changes affect React components only
- bump
packages/react-components/package.json
Both:
- changes affect both packages
- bump both package manifests
2. Update versioned files
For the package you are releasing:
- update the package
versionfield - update CHANGELOG.md
- update UPGRADING.md if the release changes the public API or install contract
3. Commit and tag
Toolkit example:
git add packages/toolkit/package.json CHANGELOG.md UPGRADING.md
git commit -m "chore(toolkit): bump version to 4.0.1"
git push origin main
git tag -a toolkit-v4.0.1 -m "Release toolkit v4.0.1"
git push origin toolkit-v4.0.1
React example:
git add packages/react-components/package.json CHANGELOG.md UPGRADING.md
git commit -m "chore(react-components): bump version to 0.5.1"
git push origin main
git tag -a react-v0.5.1 -m "Release react-components v0.5.1"
git push origin react-v0.5.1
4. GitHub Actions builds the release
When a release tag is pushed, .github/workflows/release.yml automatically:
- installs dependencies with pnpm
- runs linting and tests
- validates the release-contract docs
- prepares the package release assets in a dedicated staging directory outside the package tree
- smoke-tests the tarball with Yarn 1, npm, and pnpm
- renders release notes with the tarball install URL
- creates or updates the GitHub release
- uploads release assets
Toolkit releases upload:
ourfuturehealth-toolkit-{version}.tgzofh-design-system-toolkit-{version}.zip
React releases upload:
ourfuturehealth-react-components-{version}.tgz
5. Verify the release
After the workflow completes:
- check the GitHub Releases page
- confirm the expected
.tgzasset is attached - for toolkit, confirm the
.zipis also attached - verify the release notes show the tarball URL install contract
Toolkit release note example:
{
"dependencies": {
"@ourfuturehealth/toolkit": "https://github.com/ourfuturehealth/design-system-toolkit/releases/download/toolkit-v4.0.1/ourfuturehealth-toolkit-4.0.1.tgz"
}
}
React release note example:
{
"dependencies": {
"@ourfuturehealth/react-components": "https://github.com/ourfuturehealth/design-system-toolkit/releases/download/react-v0.5.1/ourfuturehealth-react-components-0.5.1.tgz"
}
}
Testing Before Or After Release
How release-contract validation stays current
pnpm docs:release-contract scans all tracked Markdown, shell, and workflow files in the repository rather than relying on a narrow hand-maintained file list.
It validates that:
- the broken git-subdirectory install syntax does not reappear in tracked docs or release automation
- the incorrect pre-monorepo baseline does not reappear in tracked docs
- the generated toolkit and React release notes still emit tarball install URLs
This is intentional: new docs under the normal repository conventions are picked up automatically.
CHANGELOG.md is excluded because it is a historical record and can legitimately contain superseded install strings from past releases.
If you add consumer-facing release/install docs in a different file type or move the release-note generator, update both scripts/release/validate-release-docs.sh and this section in the same change.
Smoke test the current branch artifacts
pnpm docs:release-contract
pnpm smoke:release-artifacts
This validates the public docs and then tests the current branch tarballs with Yarn 1, npm, and pnpm. It uses the same staged-asset preparation path as the tag-driven release workflow, so PR validation exercises the same artifact handoff that production releases rely on.
For local iteration you can scope this wrapper to one package and one or more package managers:
./scripts/release/smoke-current-release-artifacts.sh toolkit --managers yarn
./scripts/release/smoke-current-release-artifacts.sh react-components --managers npm,pnpm
Prepare release assets directly
If you need to inspect the exact staged assets before tagging:
./scripts/release/prepare-release-artifacts.sh toolkit
./scripts/release/prepare-release-artifacts.sh react-components
The script prints the package, version, and staged asset paths. Toolkit releases must stage both the versioned .zip and the package tarball before the workflow can create or update the GitHub release.
Test unreleased changes locally in another consumer
Toolkit:
pnpm --filter=@ourfuturehealth/toolkit run zip
npm pack ./packages/toolkit --ignore-scripts
React:
pnpm --filter=@ourfuturehealth/react-components run build
npm pack ./packages/react-components --ignore-scripts
Install the resulting .tgz file in the consumer application rather than pointing the consumer at a git branch.
Troubleshooting
Release workflow failed
Check the GitHub Actions tab and fix the failing step before re-tagging.
Common causes:
- failing tests or linting
- package build failures
- smoke test failures for the tarball install contract
- stale docs or release templates that still mention the old git-subdirectory syntax
Why release assets are staged outside the package tree
The release workflow deliberately copies built assets into a dedicated staging directory before it runs npm pack.
This is intentional. CI previously showed the toolkit createZip step completing successfully, then failed later when the workflow tried to rediscover the versioned zip from packages/toolkit/dist/. Local reproduction did not show the same disappearance, and the local/CI npm versions differed, so the release flow now treats the package working tree as unstable across later packaging steps.
The staged asset copy is the source of truth for:
- tarball smoke testing
- toolkit compiled-file uploads
- release note asset references
Consumer installation failed
Check that:
- the release has a
.tgzasset attached - the dependency points to the release tarball URL
- toolkit consumers use the
.ziponly for compiled-file installs, not package-manager installs
If you are testing unreleased code, build and pack the package locally instead of pointing the consumer at #main.
Best Practices
- Prefer package-prefixed tags:
toolkit-v*andreact-v* - Treat the release tarball as the public install contract
- Keep
.zipguidance limited to compiled-file toolkit consumers - Test every release with Yarn 1, npm, and pnpm before or during the workflow
- Update migration docs whenever the public API or install path changes