release-please
Overview
release-please automates versioning and releases by analyzing Conventional Commit messages:
- Push conventional commits to your default branch
- release-please creates/updates a Release PR with version bump and changelog
- Merge the Release PR to trigger a GitHub Release
- Publish step runs when a release is created (npm, PyPI, crates.io, etc.)
release-please handles version determination, changelog generation, and git tagging. You write good commit messages; it does the rest.
Commit Message Assistance
When a user asks for help writing a commit message (not setting up a pipeline):
- Ask what changed — "What did you change and why?" (skip if already described)
- Suggest the type — Pick from the type table below, explain why that type fits
- Draft the message — Write the full commit message (header + body if needed + footers)
- Confirm — Present it for the user to approve or adjust
If the change is breaking, always include a
footer explaining migration impact.
Pipeline Setup Flow
When a user wants to set up release-please, follow this interactive protocol.
If
.github/workflows/release.yml
(or similar) already exists, read it first, compare against the templates in
references/workflow-templates.md
, and suggest specific improvements rather than replacing it wholesale. Common improvement opportunities: missing concurrency groups, publish not gated on
, missing idempotent publish check, overly broad permissions.
Step 1: Detect Project Type
Scan the repository for package manifests:
If multiple manifests exist at the root, ask which is primary. If none found, use
.
Step 2: Ask Configuration Questions
Ask these questions (skip any already answered or obvious from context):
- Is this a monorepo? (multiple packages in subdirectories)
- What is the default branch? (default: )
- Do you need pre-release support? (manual alpha/beta/rc releases)
- Where do you publish? (npm, GitHub Packages, PyPI, Maven Central, crates.io, Docker, none)
- What is the current version? (check package manifest, default: )
Step 3: Generate Files
Create three files based on the answers:
release-please-config.json
json
{
"$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json",
"packages": {
".": {
"release-type": "node",
"changelog-path": "CHANGELOG.md",
"bump-minor-pre-major": true,
"bump-patch-for-minor-pre-major": false,
"draft": false,
"prerelease": false,
"versioning": "default",
"extra-files": []
}
}
}
Adjust
based on detected project type. For monorepos, add multiple entries under
with
names.
.release-please-manifest.json
Set to the current released version. Use
for new projects.
.github/workflows/release.yml
For Node.js → npm public registry (most common), use this base template:
yaml
name: Release
on:
push:
branches: [main]
permissions:
contents: write
pull-requests: write
concurrency:
group: release-${{ github.ref }}
cancel-in-progress: false
jobs:
release-please:
runs-on: ubuntu-latest
outputs:
release_created: ${{ steps.release.outputs.release_created }}
tag_name: ${{ steps.release.outputs.tag_name }}
version: ${{ steps.release.outputs.version }}
steps:
- uses: googleapis/release-please-action@v4
id: release
publish:
needs: release-please
if: needs.release-please.outputs.release_created == 'true'
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
registry-url: https://registry.npmjs.org
- run: npm ci
- run: npm publish --provenance --access public
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
For
other ecosystems, see
references/workflow-templates.md
for complete templates including:
- Node.js → GitHub Packages (with idempotent publish check)
- Python → PyPI (trusted publishers)
- Java → Maven Central
- Go (tags only, optional GoReleaser)
- Rust → crates.io
- Docker (build + push with semver tags)
- Monorepo (per-package publish jobs)
- Pre-release pattern (workflow_dispatch with version resolution)
Always customize:
- Replace with the actual default branch if different
- Adjust Node version, Python version, Java version, etc.
- Add registry-specific secrets configuration
- If pre-release support is needed, use the pre-release template from
references/workflow-templates.md
Configuration Quick Reference
| Option | Default | Purpose |
|---|
| — | Package ecosystem (required) |
| | Treat as patch when < 1.0.0 |
| | Where to write the changelog |
| | Tag as vs |
| | One PR per package (monorepo) |
| | Create release PRs as drafts |
| | Additional files with version strings to update |
| (defaults) | Customize which types appear in changelog |
Monorepo Quick Setup
json
// release-please-config.json
{
"packages": {
"packages/core": { "release-type": "node", "component": "core" },
"packages/cli": { "release-type": "node", "component": "cli" }
}
}
json
// .release-please-manifest.json
{ "packages/core": "0.0.0", "packages/cli": "0.0.0" }
Use component names as commit scopes:
feat(core): add streaming support
For full configuration options, see
references/config-options.md
.
Commit Message Guide
release-please reads commit messages to determine version bumps and generate changelogs. Every commit to the default branch must follow
Conventional Commits.
Format
<type>(<scope>): <description>
[optional body]
[optional footer(s)]
- Use imperative present tense: "add" not "added"
- Do not capitalize the first letter of the description
- Do not end with a period
Type → Version Bump
| Type | Bump | Triggers Release? |
|---|
| Minor | Yes |
| Patch | Yes |
| Patch | Yes |
| — | No |
| — | No |
| — | No |
| — | No |
| — | No |
| — | No |
| — | No |
| — | No |
Breaking changes (any type with
or
footer) →
Major bump.
Breaking Change Examples
feat(api)!: redesign authentication flow
BREAKING CHANGE: /auth/login now requires OAuth2 tokens instead of API keys.
refactor(database): migrate from MongoDB to PostgreSQL
BREAKING CHANGE: all database connection strings must be updated.
Special Footers
| Footer | Purpose |
|---|
| Triggers major version bump |
| Force a specific version number |
Quick Examples
feat(booking): add search by date range endpoint
fix(auth): resolve token refresh race condition
deps: upgrade @nestjs/core to v11.0.0
test(scheduler): add unit tests for cron parser
chore: update .gitignore
No AI Co-Author Trailers
NEVER add trailers for AI agents in commit messages. These pollute changelogs and git history.
For the complete commit conventions reference with 15+ examples, scopes guide, and anti-patterns, see
references/commit-conventions.md
.
Best Practices
Squash Merges
Configure your repository to use squash merges for feature branches. This ensures each PR produces a single conventional commit, keeping the changelog clean. Set the squash commit message to use the PR title (which should be a conventional commit message).
Permissions
The GitHub Action needs
and
at minimum. Add
or
for publish steps as needed. Use the principle of least privilege — grant permissions per-job, not at workflow level.
Concurrency
Always set
cancel-in-progress: false
for release workflows. Canceling a release mid-way can leave partial state (tags without releases, PRs in inconsistent state).
Publish Gating
Never publish in the release-please job itself. Use a separate
job gated on
release_created == 'true'
. This separates concerns and makes retries easier.
Idempotent Publish
Check if the version already exists in the registry before publishing. This prevents failures on workflow re-runs:
yaml
- name: Check if version exists
id: check
run: |
PACKAGE_NAME=$(node -p "require('./package.json').name")
VERSION=$(node -p "require('./package.json').version")
if npm view "${PACKAGE_NAME}@${VERSION}" version 2>/dev/null; then
echo "exists=true" >> "$GITHUB_OUTPUT"
else
echo "exists=false" >> "$GITHUB_OUTPUT"
fi
- if: steps.check.outputs.exists == 'false'
run: npm publish
Bootstrapping Existing Projects
When adding release-please to a project with existing releases:
- Set
.release-please-manifest.json
to your current version
- Merge the setup PR with a commit
- release-please will create the next release PR based on subsequent commits
- Alternatively, use footer to force a starting version
Troubleshooting
No Release PR Created
- Ensure commits since the last release include at least one releasable type (, , )
- Check that commits are on the correct branch (must match workflow trigger)
- Verify
release-please-config.json
and manifest exist and are valid JSON
- Check Actions logs for permission errors
Wrong Version Bump
- Review commit messages — won't trigger a release, triggers minor
- Check for footers that may trigger an unexpected major bump
- Use footer to override if needed
Pre-Release Flow
- Pre-releases use , not automatic push triggers
- The pre-release identifier is appended to the current version:
- Use the npm tag (or equivalent) for pre-releases, for stable
- See the pre-release template in
references/workflow-templates.md
Token / Permission Issues
- Default works for release-please PRs and releases
- Publishing to external registries requires dedicated secrets (, etc.)
- GitHub Packages publishing uses with permission
- For PyPI, use trusted publishers instead of API tokens
References
| Reference | Description |
|---|
references/commit-conventions.md
| Full Conventional Commits specification with examples and anti-patterns |
references/workflow-templates.md
| Complete workflow templates for 9 ecosystems |
references/config-options.md
| All configuration options, release types, and Action inputs/outputs |
| release-please GitHub | Official documentation |
| Conventional Commits | Specification |