Resources
1Install
npx skillscat add hitoshura25/claude-devtools/skills-npm-publishing Install via the SkillsCat registry.
NPM Publishing Setup Skill
Set up automated npm publishing with GitHub Actions for TypeScript/JavaScript packages.
Purpose
Configure automated npm publishing that publishes to npm on pushes to main and publishes RC (release candidate) versions on pull requests for testing.
What Gets Created
This skill generates 1 file:
.github/workflows/publish-{package-name}.yml- Complete publish workflow
Prerequisites
- Node.js/TypeScript project with
package.json - GitHub repository
- npm account (for NPM_TOKEN)
Process
1. Gather Project Information
From existing files:
- Read
package.jsonfor package name, version - Detect if monorepo by checking for
workspacesin root package.json - Check for
yarn.lockorpackage-lock.json
Ask user:
- Package directory: Path to package relative to repo root
- Monorepo example:
packages/my-lib - Single package:
.(root)
- Monorepo example:
- NPM package name: From package.json
namefield- Should include scope if applicable:
@scope/package-name
- Should include scope if applicable:
- Git tag prefix: Prefix for version tags
- Monorepo example:
my-lib-v(creates tags likemy-lib-v1.2.3) - Single package:
v(creates tags likev1.2.3)
- Monorepo example:
Configuration options:
- Node version: Default
20(or detect from.nvmrc,package.json engines) - NPM registry URL: Default
https://registry.npmjs.org - Build command: Default
npm install && npm run build- Adjust if using yarn:
yarn install && yarn build - Adjust if no build step:
npm install
- Adjust if using yarn:
2. Create Workflow File
Create .github/workflows/ directory:
mkdir -p .github/workflowsRead template: ./templates/workflow.yml
Substitute variables:
{{NPM_PACKAGE_NAME}}→ Package name from package.json{{PACKAGE_DIR}}→ Path to package (e.g.,packages/my-libor.){{GIT_TAG_PREFIX}}→ Tag prefix (e.g.,my-lib-vorv){{NODE_VERSION}}→ Node.js version (e.g.,20){{NPM_REGISTRY_URL}}→ Registry URL (default:https://registry.npmjs.org){{BUILD_COMMAND}}→ Build command (e.g.,npm install && npm run build)
Generate output filename:
- Slug the package name:
@scope/my-package→scope-my-package - Format:
publish-{slugged-name}.yml - Example:
publish-scope-my-package.yml
Write to: .github/workflows/publish-{slugged-name}.yml
3. User Instructions
After generating the workflow, provide instructions:
✓ NPM publishing workflow created!
File generated:
- .github/workflows/publish-{{SLUGGED_NAME}}.yml
Next steps:
1. Create NPM Access Token:
- Go to: https://www.npmjs.com/settings/YOUR_USERNAME/tokens
- Click "Generate New Token"
- Select "Automation" type
- Copy the token
2. Add NPM_TOKEN to GitHub Secrets:
- Go to: https://github.com/{{OWNER}}/{{REPO}}/settings/secrets/actions
- Click "New repository secret"
- Name: NPM_TOKEN
- Value: [paste your npm token]
- Click "Add secret"
3. Ensure package.json is configured:
- Check "name" field matches: {{NPM_PACKAGE_NAME}}
- Check "version" is set (e.g., "0.1.0")
- If scoped package (@scope/name), ensure you have publish access
- Add "files" field to specify what to publish:
{
"files": ["dist", "README.md", "package.json"]
}
4. Commit and push:
git add .github/workflows/
git commit -m "Add npm publishing workflow"
git push
5. How publishing works:
**On push to main:**
- Runs build command
- Bumps patch version automatically (0.1.0 → 0.1.1)
- Publishes to npm
- Creates git tag: {{GIT_TAG_PREFIX}}0.1.1
- Creates GitHub Release
**On pull request:**
- Runs build command
- Creates RC version: 0.1.1-rc.abc1234
- Publishes to npm with "rc" tag
- Install with: npm install {{NPM_PACKAGE_NAME}}@rc
6. Manual version bumps (if needed):
cd {{PACKAGE_DIR}}
npm version minor # 0.1.0 → 0.2.0
npm version major # 0.2.0 → 1.0.0
git push && git push --tagsValidation
Before completing, verify:
# Check workflow file exists
ls .github/workflows/publish-*.yml
# Check package.json exists in package directory
ls {{PACKAGE_DIR}}/package.json
# Validate package.json has required fields
node -e "const pkg = require('./{{PACKAGE_DIR}}/package.json'); console.log('Name:', pkg.name, 'Version:', pkg.version)"How It Works
Automatic Publishing (main branch)
Trigger: Push to main branch with changes in package directory
Process:
- Checkout code
- Setup Node.js with npm registry
- Cache dependencies (yarn cache)
- Install dependencies and build
- Bump patch version automatically
- Publish to npm
- Create and push git tag
- Create GitHub Release
RC Publishing (pull requests)
Trigger: Pull request with changes in package directory
Process:
- Checkout code
- Setup Node.js
- Cache and install dependencies
- Build package
- Create RC version (e.g.,
1.0.0-rc.abc1234) - Publish to npm with
rctag
Testing RC versions:
# Install specific RC version
npm install @scope/package@rc
# Or specific version
npm install @scope/package@1.0.0-rc.abc1234Monorepo Support
For monorepos, the workflow only runs when files in the specific package directory change:
on:
push:
paths:
- 'packages/my-lib/**'This prevents unnecessary workflow runs when other packages change.
Troubleshooting
NPM publish fails with 403:
- Check NPM_TOKEN secret is set correctly
- Verify npm token has "Automation" type (not "Read Only")
- If scoped package (@scope/name), ensure you have access to the scope
Git tag already exists:
- Workflow creates tag with current version
- If tag exists, git push --tags will fail
- Solution: Delete remote tag or bump version manually first
Build fails:
- Check BUILD_COMMAND is correct for your project
- Verify all dependencies are in package.json
- Test build locally:
cd {{PACKAGE_DIR}} && npm install && npm run build
RC versions not publishing:
- PR must have changes in package directory
- NPM_TOKEN must be set
- Check workflow runs in "Actions" tab
Wrong package gets published:
- Verify
working-directoryin workflow matches package location - Check
package.jsonin that directory has correct name
Configuration Options
All substitution variables:
{{NPM_PACKAGE_NAME}} - Full npm package name (e.g., @scope/package)
{{PACKAGE_DIR}} - Path to package (e.g., packages/my-lib or .)
{{GIT_TAG_PREFIX}} - Tag prefix (e.g., my-lib-v or v)
{{NODE_VERSION}} - Node.js version (default: 20)
{{NPM_REGISTRY_URL}} - npm registry (default: https://registry.npmjs.org)
{{BUILD_COMMAND}} - Build command (default: npm install && npm run build)
{{SLUGGED_NAME}} - Package name slugified for filename
{{OWNER}} - GitHub username or org
{{REPO}} - Repository nameBest Practices
Monorepo:
- Use unique tag prefix per package:
api-v,sdk-v,cli-v - Prevents tag conflicts between packages
- Makes it clear which package a tag belongs to
Version Management:
- Let workflow handle patch bumps automatically
- Use manual
npm versionfor minor/major bumps - Keep versions in sync between package.json and git tags
Package Configuration:
- Use
filesfield in package.json to control what's published - Include only necessary files:
["dist", "README.md", "LICENSE"] - Exclude source files, tests, configs: use
.npmignoreif needed
Testing:
- Always test RC versions from PRs before merging
- RC versions won't affect your main package
- Users must explicitly install RC versions
Output Confirmation
✓ NPM publishing configured
✓ Workflow file created
✓ package.json validated
✓ Instructions provided to userNext Steps
After setup:
- User creates NPM_TOKEN and adds to GitHub Secrets
- User commits and pushes workflow file
- On next push to main, package auto-publishes
- On PRs, RC versions available for testing