Why Does npm version Create an Automatic Commit and Tag?

Why Does npm version Create an Automatic Commit and Tag?
Photo by Mohammad Rahmani / Unsplash

If you have ever run the npm version command and suddenly noticed Git creating a commit and a tag without your explicit instruction, you are not alone. Many developers are surprised the first time they encounter this behavior. Let’s dive into what’s happening, why npm does this by default, and what options you have to control it.


What npm version Actually Does

When you run a command such as:

npm version patch

npm performs a series of actions behind the scenes:

  1. Bumps the version number in your package.json.
    • A patch bump increases 1.2.31.2.4.
    • A minor bump increases 1.2.31.3.0.
    • A major bump increases 1.2.32.0.0.
  2. Updates related files such as package-lock.json or npm-shrinkwrap.json.
  3. Creates a Git commit with the message vX.Y.Z (matching your new version).
  4. Creates a Git tag pointing to that commit.

This behavior is intentional: npm assumes you want your versioning to be tracked in Git history, which is extremely common in open source projects and for packages published to the npm registry.


Why Automatic Commits and Tags Can Be Useful

  • Version traceability: Every release is tied to a specific commit. If a bug appears in version 1.2.4, you can easily see the exact code that was published.
  • Publishing consistency: The tag ensures that the source code matches the version on npm.
  • Automation hooks: You can attach scripts to lifecycle hooks like preversion, version, and postversion in package.json for tasks such as building, testing, or publishing.

For teams practicing semantic versioning, this workflow aligns well with continuous release pipelines.


When Automatic Commits and Tags Are a Problem

However, not every project needs this behavior. Examples:

  • Private repos or internal tooling where version bumps are just for internal bookkeeping.
  • Monorepos where you handle versioning through another tool (e.g., Lerna, Changesets, or Nx).
  • Custom release processes where you want commits and tags created only after certain CI/CD checks.

In such cases, the default behavior feels intrusive.


How to Disable the Automatic Commit

To prevent Git commits and tags, you can use:

npm version patch --no-git-tag-version

This updates only your package.json (and lock file) without touching Git.

If you want this to be the default behavior for your project, set it in your .npmrc:

git-tag-version=false

From then on, npm version will only bump the numbers unless you explicitly override it.


Other Considerations

    • preversion runs before the version is bumped.
    • version runs after files are updated but before commit/tag.
    • postversion runs after commit and tagging.
  1. CI/CD and Versioning Strategy
    If your team uses a release pipeline (e.g., GitHub Actions, GitLab CI, Jenkins), you might want to centralize version bumps in CI, not on local developer machines. In that case, using --no-git-tag-version locally and letting CI handle tagging is a safer approach.
  2. Monorepo Tools Conflict
    If you’re using tools like Lerna or Changesets, those tools manage version bumps, changelogs, and tags in bulk. Mixing npm version with them can cause inconsistencies.
  3. Version Control Discipline
    Remember that automatic commits may clutter your Git history if you bump versions often. Some teams prefer manual control to keep history clean and meaningful.

Pre- and Post- Scripts
You can define lifecycle scripts in package.json:

{
  "scripts": {
    "preversion": "npm test",
    "version": "npm run build",
    "postversion": "git push && git push --tags"
  }
}

This is powerful for enforcing checks or automating deployment steps.

Custom commit messages
You can change the default commit message with:

npm version patch -m "Release version %s"

%s will be replaced with the new version number.


Best Practices

  • For open source libraries: Keep the default behavior. Commits and tags help external users trace issues.
  • For internal apps/tools: Disable Git tagging unless you publish artifacts externally.
  • For CI/CD-driven releases: Use --no-git-tag-version locally and let CI pipelines handle version commits and tags.
  • Always push tags if you rely on them for releases. Tags left only in your local repo are invisible to collaborators.

Finally

The automatic commit and tag in npm version is not a bug — it’s a deliberate feature designed for a particular workflow: reproducible, traceable releases. That said, npm gives you the flexibility to opt out if it does not suit your project.

Whether you embrace or disable this feature depends on your project’s release strategy, team workflow, and tooling ecosystem. Understanding these behaviors up front ensures you avoid unexpected commits in your history while still leveraging npm’s powerful versioning tools effectively.

Support Us

Share to Friends