| name | publish-package-cicd |
| description | CI/CD publishing workflow for npm packages using Changesets + npm Trusted Publishers (OIDC). Use when setting up automated npm publishing for monorepos, configuring GitHub Actions for releases, troubleshooting workspace:* protocol resolution issues, fixing "Cannot find module" errors in published packages, or debugging npm OIDC authentication. Covers Bun + Turborepo + Changesets + npm Trusted Publishers with workspace protocol resolution. |
Publish Package CI/CD
Automated npm publishing for Bun monorepos using Changesets + npm Trusted Publishers (OIDC). No npm tokens needed - GitHub Actions authenticates via OIDC.
Core Workflow
1. Create Changeset (Manual File Creation)
CRITICAL: Never run bunx changeset interactively. Create changeset files manually to avoid the interactive CLI:
cat > .changeset/your-change-name.md << 'EOF'
---
"package-name": patch
---
Description of the change
EOF
Version bump types:
patch- Bug fixes, minor updates (0.0.x)minor- New features, backwards compatible (0.x.0)major- Breaking changes (x.0.0)
2. Commit and Push
git add .changeset/your-change-name.md
git commit -m "feat: your feature description"
git push origin main
3. Automated Release Flow
- Changesets Action (
.github/workflows/ci.yml) detects changeset file - Creates/updates "chore: release packages" PR with version bumps + CHANGELOG
- On PR merge → triggers publish workflow (
.github/workflows/publish.yml) - Publishes to npm via OIDC (no npm token)
Trusted Publishers (OIDC) Setup
Initial Package Setup (One-Time)
For each package to publish:
Publish v0.1.0 manually:
cd packages/your-package npm publish --access publicConfigure Trusted Publisher:
- Go to https://www.npmjs.com/package/your-package/access
- Click "Trusted Publishers" → "Add"
- Fill in:
- Organization:
your-github-org - Repository:
your-repo-name - Workflow:
publish.yml
- Organization:
- Save
Future releases: Fully automated via GitHub Actions
How OIDC Works
- No
NPM_TOKENsecret required - GitHub Actions has
id-token: writepermission - npm packages configured with Trusted Publisher pointing to repo + workflow
- npm CLI 11.5.1+ auto-detects OIDC environment
- Provenance attestations generated automatically
workspace:* Protocol Resolution
Problem: workspace:* in package.json dependencies doesn't resolve during npm publish, causing "Cannot find module" errors for consumers.
Solution: Use custom publish script with two-step process:
# 1. Sync lockfile (resolves workspace:* from lockfile)
bun install
# 2. Pack tarball (resolves workspace:* to actual versions)
bun pm pack
# 3. Publish tarball (supports npm OIDC)
npm publish <tarball>
Why not bun publish? Bun resolves workspace protocols but doesn't support npm OIDC - requires npm login.
See references/publish-script.ts for full implementation.
Ignored Packages (Non-Published)
Exclude packages from publishing in .changeset/config.json:
{
"ignore": ["@swarmtools/web", "docs-app"]
}
Important: Changeset ignore only affects versioning, NOT builds. Must also exclude from turbo:
# In CI, exclude ignored packages from build
bun turbo build --filter='!@swarmtools/web'
Common Issues
CLI Bin Script "Cannot find module"
Symptom: Published package works, but CLI bin script fails with Cannot find module '@clack/prompts'.
Root cause: Bin script imports are runtime dependencies, not devDependencies.
Fix: Move ALL bin script imports to dependencies in package.json:
{
"dependencies": {
"@clack/prompts": "^0.7.0", // Used by bin/cli.ts
"commander": "^11.0.0" // Used by bin/cli.ts
}
}
Lockfile Stale After Changeset Bump
Symptom: Publish picks up old versions of workspace:* dependencies.
Root cause: bun pm pack resolves from lockfile, which is stale after version bumps.
Fix: Run bun install BEFORE bun pm pack:
bun install # Sync lockfile with new versions
bun pm pack # Now packs with correct versions
npm publish <tarball>
See references/publish-script.ts - automatically handles this.
Local bunx changeset version Fails
Symptom: Error: GITHUB_TOKEN not found
Root cause: Changesets needs GitHub API access for PR/changelog generation. Works in CI (has GITHUB_TOKEN), fails locally.
Fix: Don't run bunx changeset version or bunx changeset publish locally. Let CI handle it:
- Create changeset file manually
- Push to main
- CI creates release PR
- Merge PR → auto-publishes
Bun Publish vs npm Publish
Avoid bun publish - doesn't support npm OIDC (requires npm login).
Use npm publish <tarball> - supports OIDC + resolves workspace protocols when publishing tarball created by bun pm pack.
Reference Files
- references/publish-workflow.yml - Full GitHub Actions workflow with OIDC + workspace resolution
- references/changeset-config.json - Changeset configuration with ignored packages
- references/publish-script.ts - Custom publish script handling workspace:* resolution
Commands Reference
# Create changeset (manual file creation)
cat > .changeset/fix-thing.md << 'EOF'
---
"pkg-name": patch
---
Fixed the thing
EOF
# Preview version bumps (optional, informational only)
bunx changeset status
# Build packages (exclude ignored)
bun turbo build --filter='!@swarmtools/web'
# Publish (in CI only, via publish.yml)
bun install # Sync lockfile
bun pm pack # Create tarball with resolved workspace:*
npm publish <tarball> # Publish with OIDC
Tracking Issues
- Bun native npm token support: https://github.com/oven-sh/bun/issues/15601
- When resolved, can switch to
bun publishdirectly - Currently must use
npm publishfor OIDC support
- When resolved, can switch to