Preview Publish Workflow
The preview-publish workflow lets a ux-prototype developer ship a real, installable build of an in-progress branch to GitHub Packages. Consumers can then npm install that preview, validate against it, and feed bugs/feedback back to the design-system PR before it merges.
When to use
Section titled “When to use”- A design-system change needs consumer validation before it lands on
main. - You want CI fidelity: the consumer tests against the actual published artifact (no symlinks, no local builds).
- The change isn’t tightly coupled enough to justify coordinated multi-PR (i.e. the consumer doesn’t need to gate the design-system PR on its own CI passing).
Sequence
Section titled “Sequence”In ux-prototype
Section titled “In ux-prototype”- Branch off
main:git checkout -b <username>/<description>. - Implement the change.
- Add a pre-release CHANGELOG entry:
## [x.y.z-<author>-<id>] - YYYY-MM-DDunder the appropriate category. Examples:4.12.0-alice-FD42— Alice’s work on ticket FD-42, targeting eventual stable4.12.0.4.12.0-bob-spike-grid-virt— Bob’s spike for grid virtualization, no formal ticket.- The
<author>and<id>together form the dist-tag consumers will install by; pick something the consumer will recognize.
- Push. The
publish-preview.ymlworkflow:- Detects that CHANGELOG.md was modified.
- Validates the entry is a CLQ pre-release.
- Derives dist-tag = everything after the first
-. For4.12.0-alice-FD42, the dist-tag isalice-FD42. - Appends
github.run_numberfor uniqueness. Final published version:4.12.0-alice-FD42-7. - Publishes to GitHub Packages with
npm publish --tag alice-FD42(solatestis never disturbed).
- Iterate. Each push that modifies CHANGELOG.md publishes a new preview; the
alice-FD42dist-tag advances to point at the newest. Concurrency is keyed by branch withcancel-in-progress: true, so out-of-order pushes can’t leave the dist-tag pointing at older code. - Open a PR to
main(still with the pre-release entry). Thevalidate-releasejob will fail on this PR — that’s expected; it blocks accidental merge of a preview as stable. - Before merging, swap the changelog entry to a stable
x.y.z.validate-releasethen passes;publish-preview.ymlcorrectly skips the publish (status no longerprereleased); on merge,publish.ymlships the stable version.
In the consuming app
Section titled “In the consuming app”- Configure auth if not already done — see auth-and-tokens.
- Install the preview:
This installs whatever version the dist-tag currently points at and pins it in
Terminal window npm install @arda-cards/design-system@alice-FD42package.json/package-lock.json. - Validate locally and via your normal CI.
- Iterate: when Alice pushes new preview commits, re-run the same install command to pick up the latest. The lockfile updates with the new exact version.
- Switch back to stable before the consumer PR merges:
or pin to the specific stable that the design-system PR landed as.
Terminal window npm install @arda-cards/design-system@latest
Contracts
Section titled “Contracts”- Preview consumer’s responsibility: do not merge a consumer PR to your own
mainwhile it still references a preview dist-tag. Stable release is the merge contract. - Cleanup: previews are deleted by the cleanup workflow once the stable base ships, with a 24h grace period. Don’t leave consumer PRs using a preview series open across that boundary.
- dist-tag stability: re-running
npm install @arda-cards/design-system@alice-FD42on different days may resolve to different exact versions. Use--save-exactonly if you need that day’s exact build for reproducibility. latestis sacred:publish-preview.ymlalways uses--tag <derived>. A consumer doingnpm install @arda-cards/design-system(no tag) will never accidentally pull a preview.
Trade-offs
Section titled “Trade-offs”| Pro | Con |
|---|---|
| Real artifact, real CI fidelity | Lockfile churn on every preview bump |
| No local-environment setup needed for consumer | Consumer must remember to swap to stable before merging |
| Multiple independent previews can coexist (one per dist-tag) | Cleanup may purge a preview while a consumer PR is still using it (24h grace mitigates) |
| Decoupled iteration cadences | Slightly slower than local-side-by-side (must push + wait for CI per iteration) |
Edge cases
Section titled “Edge cases”- Two devs, same dist-tag: the dist-tag is derived from the changelog entry, not the branch name. Two devs both writing
4.12.0-alice-FD42would clobber each other. The<author>-<id>convention with<id>being a unique ticket number prevents this in practice. - Stable shipping while preview consumer PR is open: cleanup will purge the preview within 24h. Consumer should bump to the stable version (or pin to the last-known preview exact version) before the cleanup window closes.
- Pre-release that is not your branch’s: if you
npm install @arda-cards/design-system@alice-FD42and Alice pushes a new commit, the next install picks up her new code automatically. This is desired but worth knowing.
Related
Section titled “Related”- Coordinated multi-PR — when both PRs need to gate on each other’s CI
- Local side-by-side — when you need rapid two-sided iteration
- Cleanup contract — when previews disappear
Copyright: © Arda Systems 2025-2026, All rights reserved