A simple GitHub Action that updates a package.json version field based on the release/push tag that triggered the workflow. This action validates that the tag is a valid Semantic Version (SemVer) and writes the cleaned version (for example, v1.2.3 → 1.2.3) into the selected package.json file.
The action is intended for workflows triggered by release events for stable releases and pre-releases or push event with an assigned tag.
- Updates
versioninpackage.jsonwith a SemVer-cleaned value derived from the Git tag. - Validates inputs and paths using
Zodandnode:fschecks. - Uses
@npmcli/package-jsonto safely load and updatepackage.json. - Intentionally does not commit or push the changes automatically so you can control how updates are persisted.
package-json-dir-path(optional): The directory path where thepackage.jsonto update is located, relative to the repository root. If omitted or empty, the action updates the repository rootpackage.json.
Example values:
''(default) —package.jsonat the repository rootpackages/my-package—package.jsoninsidepackages/my-package
This action expects the following environment variables, which are typically wired in from your workflow:
REF(fromgithub.ref)WORKSPACE_PATH(fromgithub.workspace)
- The action validates that the provided tag is a SemVer string using
semverandZod. If invalid, the action will fail. - The action verifies the path that contains
package.jsonand fails if the file is missing. - The action loads the
package.jsonusing@npmcli/package-json, updates theversionto a cleaned SemVer (usessemver.clean), and writes it back. - This action does not automatically commit or push the resulting file changes. If you need those changes to be reflected in the repository, add a commit-and-push step to your workflow.
name: Publish to npm
on:
release:
types: [published]
permissions:
contents: read
id-token: write
jobs:
publish:
name: Publish to npm
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v6
- name: Set up Node.js
uses: actions/setup-node@v6
with:
node-version: 'lts/*'
registry-url: 'https://registry.npmjs.org'
- name: Bump package.json version
uses: TypescriptPrime/bump-packagejson-version@<version> # replace with actual version or commit hash for security
- name: Install dependencies
run: npm i
- name: Build the project
run: npm run build # use your actual build command
- name: Publish package
run: npm publish --access public # using npm's trusted publisher is recommendedname: Publish to npm
on:
release:
types: [published]
permissions:
contents: read
id-token: write
jobs:
publish:
name: Publish stable release
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v6
- name: Set up Node.js
uses: actions/setup-node@v6
with:
node-version: 'lts/*'
registry-url: 'https://registry.npmjs.org'
- name: Bump package.json version
uses: TypescriptPrime/bump-packagejson-version@<version> # replace with actual version or commit hash for security
- name: Install dependencies
run: npm i
- name: Build the project
run: npm run build # use your actual build command
- name: Publish package
run: npm publish --access public # using npm's trusted publisher is recommended
if: ${{ !contains(github.event.release.tag_name, '-') }} # only for stable releases
pre-release:
name: Publish pre-release
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v6
- name: Set up Node.js
uses: actions/setup-node@v6
with:
node-version: 'lts/*'
registry-url: 'https://registry.npmjs.org'
- name: Bump package.json version
uses: TypescriptPrime/bump-packagejson-version@<version> # replace with actual version or commit hash for security
- name: Install dependencies
run: npm i
- name: Build the project
run: npm run build # use your actual build command
- name: Publish pre-release package
run: npm publish --tag prerelease --access public # using npm's trusted publisher is recommended and replace with actual tag
if: ${{ contains(github.event.release.tag_name, '-') }} # only for pre-releasesname: 'Publish to npm'
on:
release:
types: [published]
push:
tags:
- '*.*.*-build.*'
jobs:
release:
name: Publish stable release
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write
steps:
- name: Set up NodeJS LTS
uses: actions/setup-node@v6
with:
node-version: 'lts/*'
registry-url: 'https://registry.npmjs.org'
- name: Update npm package manager
run: npm install -g npm@latest
- name: Checkout
uses: actions/checkout@v6
- name: Install dependencies
run: npm i
- name: Bump package.json version from tag
uses: TypescriptPrime/bump-packagejson-version@<version> # replace with actual version or commit hash for security
- name: Build
run: npm run build # use your actual build command
- name : Publish to npm
run: npm publish --access public # using npm's trusted publisher is recommended and replace with actual tag
if: ${{ github.event_name == 'release' && github.event.release.prerelease == false }}
pre-release:
name: Publish beta release
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write
steps:
- name: Set up NodeJS LTS
uses: actions/setup-node@v6
with:
node-version: 'lts/*'
registry-url: 'https://registry.npmjs.org'
- name: Update npm package manager
run: npm install -g npm@latest
- name: Checkout
uses: actions/checkout@v6
- name: Install dependencies
run: npm i
- name: Bump package.json version from tag
uses: TypescriptPrime/bump-packagejson-version@<version> # replace with actual version or commit hash for security
- name: Build
run: npm run build # use your actual build command
- name : Publish to npm
run: npm publish --tag prerelease --access public # using npm's trusted publisher is recommended and replace with actual tag
if: ${{ github.event_name == 'release' && github.event.release.prerelease == true && contains(github.event.release.tag_name, '-beta.') }}
build-release:
name: Build release (no publish)
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write
steps:
- name: Set up NodeJS LTS
uses: actions/setup-node@v6
with:
node-version: 'lts/*'
registry-url: 'https://registry.npmjs.org'
- name: Update npm package manager
run: npm install -g npm@latest
- name: Checkout
uses: actions/checkout@v6
- name: Install dependencies
run: npm i
- name: Bump package.json version from tag
uses: TypescriptPrime/bump-packagejson-version@<version> # replace with actual version or commit hash for security
- name: Build
run: npm run build # use your actual build command
- name : Publish to npm
run: npm publish --tag build --access public # using npm's trusted publisher is recommended and replace with actual tag
if: ${{ github.event_name == 'push' && startsWith(github.ref, 'refs/tags/') && contains(github.ref, '-build.') }}- The workflow works correctly when releasing a release with a tag.
- The action receives
REFandWORKSPACE_PATHfrom the workflow and runsindex.tswith the appropriate arguments. index.tsvalidates the tag andpackage.jsonpath usingZodandnode:fschecks.- The action loads the
package.json, setsversiontosemver.clean(tag), and writes the file back to disk.
package-json-dir-pathincorrect or file not found: Confirm that the path you pass is the directory containingpackage.json, relative to the repo root.- Invalid tag format: Ensure your tag matches SemVer (e.g.,
v1.2.3or1.2.3). - Changes not visible in repo: Remember that the action modifies the file in the runner workspace but doesn't commit/push by default. Add a commit/push step if you want to persist it.
- Push permission errors: Use
persist-credentials: trueinactions/checkoutandGITHUB_TOKENor a suitable secret user token if pushing commits.
This repository follows the LICENSE file included with the project.
- This action is meant to be a simple automation to synchronize a package.json version to the release tag version. It is intentionally minimal to make it flexible for different CI flows.
- If you need automatic version bump commits and/or publishing to the registry, add additional workflow steps or a separate release step after committing the new version.