| name | bun-publishing |
| description | Publish npm packages built with Bun: package.json config, CLI tool packaging, provenance signing, release automation. Use when setting up `publishConfig`/`files`/`bin`, packaging a CLI, enabling `--provenance`, or wiring release-please. |
| user-invocable | false |
| allowed-tools | Bash, Read, Write, Edit, Grep, Glob, TodoWrite |
| created | "2025-12-21T00:00:00.000Z" |
| modified | "2026-06-06T00:00:00.000Z" |
| reviewed | "2026-06-06T00:00:00.000Z" |
Bun npm Publishing
When to Use This Skill
| Scenario | Use this skill | Alternative |
|---|
| Configuring package.json for npm publishing | Yes | N/A |
| Publishing a package to npm registry | Yes | N/A |
Setting up CLI tool packaging with bin | Yes | N/A |
| Configuring provenance signing | Yes | N/A |
| Setting up release-please automation | Yes | N/A |
| Validating tarball contents before publish | Yes | N/A |
| Installing or updating dependencies | No - use bun-package-manager | bun-add for quick additions |
| Building/bundling before publish | No - use bun-development | bun-build for quick builds |
Core Expertise
Publishing npm packages built with Bun:
- Package.json configuration for npm registry
- CLI tool packaging with executable binaries
- Provenance signing for supply chain security
- Release automation with release-please
Package.json Configuration
Essential Publishing Fields
{
"name": "@org/package-name",
"version": "1.0.0",
"description": "Package description",
"main": "build/index.js",
"type": "module",
"publishConfig": {
"access": "public"
},
"files": [
"build/",
"README.md",
"LICENSE"
],
"scripts": {
"build": "tsc && chmod +x build/index.js",
"prepublishOnly": "bun run build"
},
"engines": {
"node": ">=20.0.0",
"bun": ">=1.0.0"
}
}
Field Reference
| Field | Purpose |
|---|
publishConfig.access | public required for scoped packages |
files | Whitelist of files/dirs to include in tarball |
main | Entry point for CommonJS/ES import |
type | module for ESM, commonjs for CJS |
engines | Runtime version requirements |
prepublishOnly | Runs before npm publish |
Scoped Packages
Scoped packages (@org/name) require explicit public access:
{
"name": "@myorg/mypackage",
"publishConfig": {
"access": "public"
}
}
Or use the CLI flag:
npm publish --access public
CLI Tool Packaging
Binary Entry Configuration
{
"bin": {
"mycli": "build/index.js"
}
}
For single-command packages:
{
"bin": "build/index.js"
}
Executable Setup
Entry point requires shebang and executable permission:
#!/usr/bin/env node
import { main } from "./main.js";
main();
Build script must set permissions:
{
"scripts": {
"build": "tsc && chmod +x build/index.js"
}
}
Makefile Integration
build-prod:
rm -rf build
tsc --declaration --sourceMap
chmod +x build/index.js
publish: build-prod
npm publish --access public
Publishing Commands
Manual Publishing
npm publish
npm publish --access public
npm publish --dry-run
npm pack --dry-run
With Provenance
Supply chain security via npm provenance:
npm publish --provenance --access public
Requires:
- CI environment (GitHub Actions, GitLab CI)
id-token: write permission in workflow
- npm registry-url configured
Files Whitelist
Recommended Pattern
{
"files": [
"build/",
"README.md",
"LICENSE"
]
}
What to Include
| Include | Examples |
|---|
| Build output | build/, dist/ |
| Type definitions | *.d.ts (usually in build) |
| Documentation | README.md, LICENSE |
| Config scripts | User-facing setup scripts |
What to Exclude
Already excluded by npm (no need to list):
node_modules/
.git/
.env*
*.log
Explicitly exclude via .npmignore if needed:
src/
tests/
*.test.ts
.github/
Release Automation
Release-Please Integration
.github/workflows/release-please.yml:
name: Release Please
on:
push:
branches: [main]
permissions:
contents: write
pull-requests: write
id-token: write
jobs:
release-please:
runs-on: ubuntu-latest
outputs:
release_created: ${{ steps.release.outputs.release_created }}
steps:
- uses: google-github-actions/release-please-action@v4
id: release
with:
release-type: node
package-name: mypackage
publish:
needs: release-please
if: ${{ needs.release-please.outputs.release_created == 'true' }}
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 24
registry-url: https://registry.npmjs.org
- uses: oven-sh/setup-bun@v2
with:
bun-version: latest
- run: bun install --frozen-lockfile
- run: bun run build
- run: npm publish --provenance --access public
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
Conventional Commits for Versioning
| Commit Type | Version Bump |
|---|
feat: | Minor (1.x.0) |
fix: | Patch (1.0.x) |
feat!: or BREAKING CHANGE: | Major (x.0.0) |
chore:, docs:, refactor: | No bump |
Pre-publish Validation
Build Hook
{
"scripts": {
"prepublishOnly": "bun run build"
}
}
Full Validation
bun run tsc --noEmit
bun run check
bun test
bun run build
npm pack --dry-run
Repository Metadata
Complete metadata for npm and GitHub:
{
"repository": {
"type": "git",
"url": "https://github.com/org/repo.git"
},
"homepage": "https://github.com/org/repo#readme",
"bugs": {
"url": "https://github.com/org/repo/issues"
},
"keywords": ["keyword1", "keyword2"],
"author": "Name <email>",
"license": "MIT"
}
Agentic Optimizations
| Context | Command |
|---|
| Preview tarball | npm pack --dry-run |
| Preview publish | npm publish --dry-run |
| Scoped publish | npm publish --access public |
| Provenance | npm publish --provenance --access public |
| Check outdated | npm outdated |
| View package | npm view @org/pkg |
Quick Reference
Publishing Flags
| Flag | Description |
|---|
--access public | Required for scoped packages |
--provenance | Enable supply chain provenance |
--dry-run | Preview without publishing |
--tag <tag> | Publish with dist-tag (e.g., beta) |
Package.json Scripts
| Script | When It Runs |
|---|
prepublish | Before pack and publish (deprecated) |
prepublishOnly | Before publish only |
prepack | Before pack and publish |
postpack | After pack |
postpublish | After publish |
CI Environment Variables
| Variable | Purpose |
|---|
NODE_AUTH_TOKEN | npm authentication |
NPM_TOKEN | Alternative npm token name |
Common Issues
Scoped package 402 error:
npm publish --access public
Missing files in tarball:
npm pack --dry-run
Binary not executable after install:
chmod +x build/index.js
2FA publish (EOTP) is not automatable:
A non-interactive shell — a CI step, or an agent's Bash tool — cannot
supply a one-time password. npm publish fails with:
npm error code EOTP
npm error This operation requires a one-time password.
Two ways through:
- Human, interactive:
npm publish --otp=<6-digit-code> (the code
comes from the publisher's authenticator app, not from npm on demand).
- Automation token (CI / unattended): a Granular/Automation token
(npmjs.com → Access Tokens) bypasses 2FA at publish time. Put it in
NODE_AUTH_TOKEN / NPM_TOKEN. This is exactly why the release-please
workflow above publishes cleanly while a local npm publish prompts —
CI uses the token, the human uses the OTP.
An agent that hits EOTP should hand the publish to the user or switch
the repo to an automation token — it cannot mint or supply one itself
(npm token create also requires a valid, OTP-satisfied session).
Fresh publish 404s for a few minutes (propagation lag):
Right after a first publish, public / unauthenticated reads can 404
while the package is genuinely live — the access record updates instantly
but the public metadata CDN lags. Don't conclude the publish failed.
Confirm with authenticated, version-pinned checks:
npm access list packages
npm view @org/pkg@<version> _id
npm pack @org/pkg@<version>
Signature of propagation lag (not a private/failed publish): a public
404 plus npm access list packages shows the package plus an
authed npm pack @org/pkg@<version> succeeds. (npm config get //registry.npmjs.org/:_authToken often returns empty even when logged
in, so a hand-rolled curl with that "token" is an unauthenticated probe
— use the npm CLI itself, which reads auth correctly, to test.)