EN
project

Releases

How astro-ignite is versioned and shipped to npm — the two-package CLI, stable releases, and per-PR betas.

Last updated

The two packages

astro-ignite ships as two npm packages that always publish together at the same version:

PackageWhat it is
astro-igniteThe primary CLI. Subcommand-based: bootstrap today, add / upgrade planned.
create-astro-igniteA thin shim that exists so npm create astro-ignite@latest works. Delegates to astro-ignite bootstrap.

Both invocations reach the same code:

terminal bash
npm create astro-ignite@latest my-site     # shim → spawns the line below
npx astro-ignite@latest bootstrap my-site  # direct

The two-package split exists because the create-* convention is the discoverable install (every Astro/Vite/Next scaffolder uses it), but a single binary with subcommands is the cleaner UX once we add astro-ignite add <component> and astro-ignite upgrade. Shipping both gives users both UXes.

Two release channels

ChannelTriggernpm dist-tagVersion shape
StableMerging the auto-opened Version Packages PR on mainlatestsemver, e.g. 0.1.0
BetaLabeling any open PR with 🚀 autoreleasebeta0.0.0-beta.<short-sha>

Both flows share one workflow file: .github/workflows/release.yml, modeled on shadcn-ui/ui.

Stable releases

Triggered automatically by every push to main. Maintained via Changesets.

write changes  →  pnpm changeset  →  git push  →  PR + merge to main


                            workflow runs on main, action sees
                            pending changesets and opens (or
                            updates) the "Version Packages" PR
                            on branch `changeset-release/main`

                                                       │  (whenever you're ready)

                            merge the Version Packages PR


                            workflow runs again, no pending
                            changesets remain → `changeset publish`
                            ships both packages to npm as @latest

Implementation detail: the version step calls .github/changeset-version.js (a thin wrapper) which runs changeset version and then pnpm install --lockfile-only so the Version Packages PR carries a fresh pnpm-lock.yaml.

Beta releases

Triggered when a maintainer adds the 🚀 autorelease label to an open PR against main.

open a PR with your changes  →  add the "🚀 autorelease" label


                              workflow's prerelease job runs:
                                1. checkout the PR head
                                2. node .github/version-script-beta.js
                                   → rewrites packages/astro-ignite/package.json
                                     and packages/create-astro-ignite/package.json
                                     to version `0.0.0-beta.<short-sha>`
                                3. build both packages
                                4. npm publish --tag beta --access public
                                   for each
                                5. upload the built tarball as a workflow artifact

The version bump is NOT committed — it only lives in the published tarballs. Each new push to the same PR can be re-published by removing and re-adding the label.

Install a beta:

terminal bash
npm create astro-ignite@beta my-site               # latest beta
npm create astro-ignite@0.0.0-beta.abc123 my-site  # pin to a specific PR build
npx astro-ignite@beta bootstrap my-site            # direct, latest beta

Beta versions never become @latest. Users have to opt in explicitly.

Writing a changeset

For every change that should ship to users:

terminal bash
pnpm changeset

Interactive prompt: pick the bump type (patch | minor | major) and write a one-line summary. A markdown file lands in .changeset/. Commit it alongside your code change.

Bump-type rules of thumb:

  • patch — bug fix, doc fix, internal refactor with no behavior change.
  • minor — new feature, new template, new prompt, new flag.
  • major — breaking change to CLI flags, generated project layout, or template contract.

The astro-ignite and create-astro-ignite packages are linked in .changeset/config.json — bumping one always bumps the other to the same version. The shim is tightly coupled to the CLI binary it delegates to.

Files involved

PathPurpose
.github/workflows/release.ymlThe two-job workflow (stable + beta).
.github/changeset-version.jsStable: changeset version + lockfile refresh.
.github/version-script-beta.jsBeta: rewrite both packages’ versions to 0.0.0-beta.<sha>.
.changeset/config.jsonchangesets config (access, ignore list, linked packages).
.changeset/*.mdPending change descriptions, consumed at release time.

Required setup

This is one-time-per-repo setup. Already done for astro-ignite, listed here for forks.

  • GitHub Environment Prod with secret NPM_TOKEN — npm Granular Access Token, Bypass 2FA checkbox ticked, scope Read and write on All packages (Granular tokens can’t be scoped to a non-existent package; rotate to a narrower one after first publish).
  • Repository label 🚀 autorelease — color green (#0E8A16).
  • Settings → Actions → General → Workflow permissions → ✅ Allow GitHub Actions to create and approve pull requests (required so the Version Packages PR can be opened).

Troubleshooting

“GitHub Actions is not permitted to create or approve pull requests” — flip the toggle in repo Settings → Actions → General → Workflow permissions.

npm error code ENEEDAUTH — the secret didn’t resolve. Either the workflow job is missing environment: Prod, or NPM_TOKEN isn’t in the Prod environment.

npm error code EOTP — the token doesn’t bypass 2FA. Regenerate a Granular Access Token with the Bypass two-factor authentication (2FA) checkbox ticked.

npm error 403 Forbidden on first publish — your npm account email isn’t verified. Confirm via the email link sent at signup.

Version Packages PR doesn’t appear after merging changesets — check .changeset/ contains .md files besides README.md and config.json. The action only opens a PR when there are unconsumed changesets.

Beta job doesn’t run after labeling — the label is 🚀 autorelease exactly (rocket emoji + single space + autorelease), and the PR targets main. Forks can’t publish; the job’s if: checks github.repository_owner.

Future upgrades

Tracked, not yet done:

  • npm OIDC trusted publishers — replace NPM_TOKEN with OIDC so there’s no long-lived secret in the repo. Requires configuring trusted publishers on each package’s npm settings page.
  • Pin the shim to its own versioncreate-astro-ignite currently spawns astro-ignite@latest. After stable releases exist, npm create astro-ignite@beta would run the stable CLI, not the beta. The shim should spawn astro-ignite@<its-own-version>.
  • Demote latest post-first-publish — npm’s first-publish quirk sets latest even with --tag beta. Add a workflow step to npm dist-tag rm <pkg> latest on the very first beta publish, or accept it and let the first stable release overwrite latest.