DEV Community

Hansel Wei
Hansel Wei

Posted on

Automate Node.js Version Bumps with GitHub Actions (No Manual PRs Needed)

Manually bumping a package version is one of those low-value chores that's easy to forget, easy to mess up, and just annoying enough to interrupt your flow. You change package.json, regenerate the lockfile, commit it, open a PR — every time, for every release.

There's a better way: let a GitHub Actions workflow handle the entire thing on demand.

Here's an example project with the workflow pattern I set up for one of my open source dev tool line-commenter-tool, which you can adapt for any Node.js project.


What It Does

When you're ready to cut a new version, you trigger a workflow dispatch from the GitHub Actions UI (or via the API/CLI). The workflow:

  1. Checks out your target branch
  2. Bumps the version in package.json
  3. Runs npm ci to regenerate package-lock.json
  4. Opens a pull request with a clean commit and auto-generated description

The resulting PR looks similar to this:

chore: bump version to 2.1.0

  • Updated package.json version to 2.1.0
  • Regenerated package-lock.json
  • Verified install with npm ci

Triggered via workflow dispatch by @hansel

No manual work. No forgotten lockfile updates. Just review and merge.


The Workflow

Create .github/workflows/bump-version.yml:

name: Bump Version

on:
  workflow_dispatch:
    inputs:
      version:
        description: "New version (e.g. 2.1.0)"
        required: true
      target_branch:
        description: "Branch to bump version on"
        required: true
        default: "main"

jobs:
  bump:
    runs-on: ubuntu-latest
    permissions:
      contents: write
      pull-requests: write

    steps:
      - name: Checkout
        uses: actions/checkout@v4
        with:
          ref: ${{ github.event.inputs.target_branch }}

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: "lts/*"

      - name: Bump version in package.json
        run: |
          npm version ${{ github.event.inputs.version }} --no-git-tag-version

      - name: Verify install
        run: npm ci

      - name: Create PR branch and push
        run: |
          git config user.name "github-actions[bot]"
          git config user.email "github-actions[bot]@users.noreply.github.com"
          git checkout -b chore/bump-version-${{ github.event.inputs.version }}
          git add package.json package-lock.json
          git commit -m "chore: bump version to ${{ github.event.inputs.version }}"
          git push origin chore/bump-version-${{ github.event.inputs.version }}

      - name: Open Pull Request
        uses: actions/github-script@v7
        with:
          script: |
            const { data: pr } = await github.rest.pulls.create({
              owner: context.repo.owner,
              repo: context.repo.repo,
              title: "chore: bump version to ${{ github.event.inputs.version }}",
              head: "chore/bump-version-${{ github.event.inputs.version }}",
              base: "${{ github.event.inputs.target_branch }}",
              body: `## Version Bump\n\nBumps the package version from the current version to \`${{ github.event.inputs.version }}\`.\n\n### Changes\n\n- Updated \`package.json\` version to \`${{ github.event.inputs.version }}\`\n- Regenerated \`package-lock.json\`\n- Verified install with \`npm ci\`\n\n---\n\n*Triggered via workflow dispatch by @${{ github.actor }}*`
            });
            console.log(`PR created: ${pr.html_url}`);
Enter fullscreen mode Exit fullscreen mode

How to Use It

From the GitHub UI:

  1. Go to your repo → Actions tab
  2. Select Bump Version from the left sidebar
  3. Click Run workflow
  4. Enter the new version number and target branch
  5. Hit Run workflow

Within seconds, a PR appears targeting your branch. Review the diff (should just be package.json and package-lock.json), then merge.

From the CLI with gh:

gh workflow run bump-version.yml \
  -f version=2.1.0 \
  -f target_branch=my-feature-branch
Enter fullscreen mode Exit fullscreen mode

Why This Pattern Works Well

It fits into your existing review process. The version bump goes through a PR like any other change. You get to review it, run your CI checks, and merge intentionally.

The bot commit is honest. The commit is attributed to github-actions[bot], so your git history clearly shows which bumps were automated versus manual. No noise in your contributor graph.

It handles the lockfile correctly. Running npm ci after the version bump ensures the lockfile is consistent. This catches any edge cases where a stale lockfile might cause issues downstream.

It targets feature branches, not just main. Because target_branch is an input, you can bump the version on a release branch or a feature branch mid-development — useful when you're preparing multiple releases in parallel.


Variations Worth Considering

Auto-detect the current version and increment it: Instead of specifying the full version, accept a bump type (patch, minor, major) and use npm version patch --no-git-tag-version to let npm calculate it.

- name: Bump version
  run: npm version ${{ github.event.inputs.bump_type }} --no-git-tag-version
Enter fullscreen mode Exit fullscreen mode

Auto-merge on approval: Add a pull_request_review trigger or use a merge queue to automatically merge version bump PRs after CI passes, removing the need to manually merge them.

Tag the release after merge: Chain a second workflow that listens for merged PRs with the chore/bump-version-* naming pattern and creates a git tag automatically.


Wrapping Up

This is a small workflow but it removes a surprisingly persistent source of friction. Once it's in place, you stop thinking about version bumps entirely — you just trigger the workflow, review the PR, and merge.

The full example is live in the line-commenter-tool repo if you want to see what the generated PR looks like in practice.


Have a variation of this pattern that works well for your project? Drop it in the comments.

Top comments (0)