npm 17 ๐ Version Management (npm version patch|minor|major)
Version management is the discipline of incrementing a package’s version number in a way that communicates the nature of the change to the consumers who depend on it. The npm version command automates this increment, writing the new version to package.json and package-lock.json, andโwhen run inside a Git repositoryโcreating a commit and a tag that mark the release . The three primary arguments correspond to the three levels of semantic versioning: patch for backward-compatible fixes, minor for backward-compatible features, and major for breaking changes .
Key point: npm version patch on a prerelease version does not increment the patch number. It removes the prerelease suffix. 1.2.0-5 becomes 1.2.0, not 1.2.1 . This is the one behavior that contradicts the intuition that “patch always increments the third digit.”
Why npm version exists
The manual increment problem. A package’s version number lives in package.json. A developer can edit it by hand, but that edit does not update package-lock.json, does not create a Git tag, and does not run any validation scripts. The npm version command performs all three operations from a single input, ensuring that the version number in the manifest, the lockfile, and the Git history are consistent . The manual approach invites the drift that produces a published package whose tag does not match its contents.
The semantic meaning problem. A version number is a contract. A patch release tells consumers that upgrading is safe. A major release tells them that something might break. The npm version command enforces the semantic distinction by requiring the developer to choose the level explicitly. The command does not know whether the change is breaking; the developer does. But the command ensures that the chosen level is applied consistently across the artifacts that record it .
The Git integration problem. A release is a point in history that should be identifiable. The npm version command creates a commit with the message vX.Y.Z (or a custom message) and a tag with the same name. This tag is what npm publish uses to associate the published tarball with a specific point in the repository, and it is what tools like from-git read to determine the next version . Without the tag, the release exists only as a tarball in the registry, disconnected from the source history.
a. The Three Increment Levels
The semantic versioning specification defines three numbers separated by dots: MAJOR.MINOR.PATCH. The npm version command increments one of these numbers and resets the lower numbers according to the rules of the specification .
| Command | Before | After | Meaning |
|---|---|---|---|
npm version patch | 1.0.0 | 1.0.1 | Backward-compatible bug fix |
npm version minor | 1.0.1 | 1.1.0 | Backward-compatible new feature |
npm version major | 1.1.0 | 2.0.0 | Breaking change |
The patch increment changes the third digit and leaves the first two unchanged. The minor increment changes the second digit, resets the third to zero, and leaves the first unchanged. The major increment changes the first digit, resets the second and third to zero . The pattern is consistent: increment the target digit, reset everything to its right.
The command also accepts explicit version strings, prerelease variants (prepatch, preminor, premajor, prerelease), and from-git, which reads the latest Git tag and uses it as the new version . The prerelease variants produce versions like 1.1.0-0, which are useful for publishing test builds that should not satisfy a ^1.0.0 range.
b. Git Integration and the Commit-Tag Workflow
When npm version runs inside a Git repository, it performs four operations in sequence: it checks that the working directory is clean, runs the preversion script if one exists, bumps the version in package.json, and creates a commit and tag . The clean-directory check is a safety measure: if there are uncommitted changes, the version commit would either include them unintentionally or fail to include files that the version script generates.
# Bump the patch version and create a commit and tag
npm version patch
# The output shows the new version and the tag
# v1.0.1
The commit message defaults to the version number prefixed with v. The -m flag provides a custom message, and the %s placeholder is replaced with the new version number .
# Custom commit message with the version number interpolated
npm version patch -m "Release %s"
The tag is lightweight by default. The sign-git-tag configuration option, when set to true, signs the tag with GPG, which provides a cryptographic assertion that the tag was created by the holder of the private key . This is optional but recommended for packages that are distributed to untrusted consumers.
The git-tag-version configuration option controls whether the commit and tag are created at all. Setting it to false suppresses both operations, which is useful when the version bump is part of a larger release process that manages Git separately . The command-line flag --no-git-tag-version achieves the same effect for a single invocation.
c. Lifecycle Scripts and the Release Pipeline
The preversion, version, and postversion scripts are lifecycle hooks that run at specific points during the npm version command. They allow the release process to include tests, builds, and cleanup without manual intervention .
The order is fixed and matters. The preversion script runs before the version is bumped, with access to the old version. A typical use is running the full test suite; if the tests fail, the version bump does not happen . The version script runs after the bump, with access to the new version. A typical use is building the distribution files and adding them to the commit . The postversion script runs after the commit and tag are created, with access to the new version. A typical use is pushing the commit and tag to the remote .
{
"scripts": {
"preversion": "npm test",
"version": "npm run build && git add -A dist",
"postversion": "git push && git push --tags"
}
}
The version script must explicitly git add any files it generates. The npm version command commits only the files that are already staged or tracked. A build script that generates dist/ files without staging them produces a tag that does not include the built artifacts. The git add -A dist in the example above is not decorative; it is the step that includes the build output in the version commit.
The environment variables npm_old_version and npm_new_version are available to these scripts, which allows conditional logic based on the version transition .
Complete Example Session
# ============================================
# PART 1: CHECK THE CURRENT VERSION
# ============================================
# The version is in package.json
cat package.json | grep '"version"'
# "version": "1.0.0"
# ============================================
# PART 2: BUMP A PATCH VERSION
# ============================================
# For a backward-compatible bug fix
npm version patch
# Output: v1.0.1
# package.json now has "version": "1.0.1"
# A Git commit and tag are created
# ============================================
# PART 3: BUMP A MINOR VERSION
# ============================================
# For a backward-compatible new feature
npm version minor
# Output: v1.1.0
# The minor digit increments, the patch resets to 0
# ============================================
# PART 4: BUMP A MAJOR VERSION
# ============================================
# For a breaking change
npm version major
# Output: v2.0.0
# The major digit increments, minor and patch reset
# ============================================
# PART 5: CUSTOM COMMIT MESSAGE
# ============================================
npm version patch -m "Upgrade to %s for security fix"
# The %s is replaced with the new version number
# Commit message: "Upgrade to 2.0.1 for security fix"
# ============================================
# PART 6: SKIP THE GIT TAG
# ============================================
# When the release process manages Git separately
npm --no-git-tag-version version patch
# Version is bumped, but no commit or tag is created
# ============================================
# PART 7: PRERELEASE VERSION
# ============================================
# For a test build that should not satisfy a range
npm version prerelease --preid=beta
# Output: v2.0.1-beta.0
# ============================================
# PART 8: LIFECYCLE SCRIPTS
# ============================================
# package.json scripts:
# "preversion": "npm test",
# "version": "npm run build && git add -A dist",
# "postversion": "git push && git push --tags"
#
# npm version patch executes:
# 1. npm test (preversion)
# 2. Version bump
# 3. npm run build && git add -A dist (version)
# 4. Git commit and tag
# 5. git push && git push --tags (postversion)
# ============================================
# PART 9: VERIFY THE TAG
# ============================================
# List the Git tags
git tag -l
# Output includes v2.0.1
# Show the tag's commit
git show v2.0.1
# ============================================
# PART 10: PUBLISH THE NEW VERSION
# ============================================
# After the version bump and tag, publish to the registry
npm publish
# The published version is v2.0.1
The ten parts trace the three increment levels, the custom message, the skip-tag option, the prerelease variant, and the lifecycle scripts. Part 6 shows the flag that disables Git integration, which is the escape hatch when the version bump is part of a larger process.
Quick Reference
Increment Levels
| Command | 1.0.0 becomes | When to Use |
|---|---|---|
npm version patch | 1.0.1 | Backward-compatible fix |
npm version minor | 1.1.0 | Backward-compatible feature |
npm version major | 2.0.0 | Breaking change |
npm version prerelease --preid=beta | 1.0.1-beta.0 | Test build |
Git Integration Options
| Option | Effect |
|---|---|
| (default) | Commit and tag created |
--no-git-tag-version | No commit, no tag |
-m "message %s" | Custom commit message |
sign-git-tag=true | GPG-signed tag |
Lifecycle Scripts
| Script | Runs When | Access To |
|---|---|---|
preversion | Before bump | Old version |
version | After bump, before commit | New version |
postversion | After commit and tag | New version |
Files Updated
| File | Updated |
|---|---|
package.json | Yes |
package-lock.json | Yes |
npm-shrinkwrap.json | Yes, if present |
Best Practices
โ Do This:
# Use patch for backward-compatible fixes
npm version patch # โ
# Use a custom message that includes the version
npm version minor -m "Release %s" # โ
# Run tests in preversion to block the bump on failure
"preversion": "npm test" # โ
# Stage generated files in the version script
"version": "npm run build && git add -A dist" # โ
# Push the commit and tag in postversion
"postversion": "git push && git push --tags" # โ
โ Don’t Do This:
# Use major for a bug fix
npm version major # overstates the change # โ
# Use patch for a breaking change
npm version patch # understates the change # โ
# Forget to stage build output in the version script
# The tag will not include the built files # โ
# Run npm version with a dirty working directory
# It fails unless --force is used # โ
# Assume patch increments a prerelease's patch number
# 1.2.0-5 becomes 1.2.0, not 1.2.1 # โ
Common Pitfalls
| Pitfall | Why It Happens | Fix |
|---|---|---|
| Version bump fails | Working directory has uncommitted changes | Commit or stash changes first |
| Tag missing from remote | postversion push not configured | Add git push --tags to postversion |
| Build artifacts not in tag | version script did not git add | Stage files explicitly |
| Prerelease version does not increment | patch removes suffix instead | Use prerelease explicitly |
| Tag is unsigned | sign-git-tag not set | npm config set sign-git-tag true |
Real-World Examples
1. Patch Release
npm version patch
2. Minor Release
npm version minor
3. Major Release
npm version major
4. Prerelease
npm version prerelease --preid=rc
5. Custom Message
npm version patch -m "Fix %s"
6. Skip Git Tag
npm --no-git-tag-version version patch
7. Preversion Test
"preversion": "npm test"
8. Version Build
"version": "npm run build && git add -A dist"
9. Postversion Push
"postversion": "git push && git push --tags"
10. Verify Tag
git tag -l && git show v1.0.1
Visual
Semantic Versioning Structure
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ MAJOR.MINOR.PATCH โ
โ โ
โ 1.0.0 โ
โ โ โ โ โ
โ โ โ โโโ PATCH: backward-compatible bug fix โ
โ โ โโโโโ MINOR: backward-compatible feature โ
โ โโโโโโโ MAJOR: breaking change โ
โ โ
โ npm version patch โ 1.0.1 โ
โ npm version minor โ 1.1.0 โ
โ npm version major โ 2.0.0 โ
โ โ
โ When a digit increments, all digits to its right reset. โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
The npm version Execution Order
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ npm version patch โ
โ โ โ
โ โผ โ
โ โโโโโโโโโโโโโโโโโโโ โ
โ โ 1. Check Git โ Working directory clean? โ
โ โ clean โ Fail if not (unless --force) โ
โ โโโโโโโโโโฌโโโโโโโโโ โ
โ โผ โ
โ โโโโโโโโโโโโโโโโโโโ โ
โ โ 2. preversion โ Runs tests, old version available โ
โ โ script โ โ
โ โโโโโโโโโโฌโโโโโโโโโ โ
โ โผ โ
โ โโโโโโโโโโโโโโโโโโโ โ
โ โ 3. Bump version โ package.json + lockfile โ
โ โโโโโโโโโโฌโโโโโโโโโ โ
โ โผ โ
โ โโโโโโโโโโโโโโโโโโโ โ
โ โ 4. version โ Build, git add generated files โ
โ โ script โ New version available โ
โ โโโโโโโโโโฌโโโโโโโโโ โ
โ โผ โ
โ โโโโโโโโโโโโโโโโโโโ โ
โ โ 5. Commit โ Message: v1.0.1 (or custom) โ
โ โ and tag โ Tag: v1.0.1 โ
โ โโโโโโโโโโฌโโโโโโโโโ โ
โ โผ โ
โ โโโโโโโโโโโโโโโโโโโ โ
โ โ 6. postversion โ Push, cleanup โ
โ โ script โ โ
โ โโโโโโโโโโโโโโโโโโโ โ
โ โ
โ The order is fixed. Each script has access to a specific โ
โ version state. โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Prerelease Behavior
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ CURRENT: 1.2.0-5 โ
โ โ
โ npm version patch โ
โ โ โ
โ โผ โ
โ โโโโโโโโโโโโโโโโโโโ โ
โ โ Removes the โ Result: 1.2.0 โ
โ โ prerelease โ NOT 1.2.1 โ
โ โ suffix โ โ
โ โโโโโโโโโโโโโโโโโโโ โ
โ โ
โ CURRENT: 1.2.0 โ
โ โ
โ npm version patch โ
โ โ โ
โ โผ โ
โ โโโโโโโโโโโโโโโโโโโ โ
โ โ Increments the โ Result: 1.2.1 โ
โ โ patch digit โ โ
โ โโโโโโโโโโโโโโโโโโโ โ
โ โ
โ The prerelease state changes the meaning of patch. โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Git Tag and Publish
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ npm version minor โ
โ โ โ
โ โโโ package.json โ 1.1.0 โ
โ โโโ Git commit โ "v1.1.0" โ
โ โโโ Git tag โ "v1.1.0" โ
โ โ
โ npm publish โ
โ โ โ
โ โผ โ
โ โโโโโโโโโโโโโโโโโโโ โ
โ โ Registry โ Tarball published โ
โ โ โ Associated with tag v1.1.0 โ
โ โโโโโโโโโโโโโโโโโโโ โ
โ โ
โ The tag connects the published artifact to a โ
โ specific point in the Git history. โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Summary
| Item | Value |
|---|---|
| Patch | 1.0.0 โ 1.0.1; backward-compatible fix |
| Minor | 1.0.1 โ 1.1.0; backward-compatible feature |
| Major | 1.1.0 โ 2.0.0; breaking change |
| Files updated | package.json, package-lock.json |
| Git integration | Commit and tag created by default |
| Skip Git | --no-git-tag-version |
| Custom message | -m "message %s" |
| Prerelease patch | Removes suffix, does not increment |
| Lifecycle order | preversion โ bump โ version โ commit/tag โ postversion |
Key takeaways:
- The increment level is a communication decision, not a mechanical one.
patchtells consumers the change is safe.majortells them something might break. The command applies the chosen level consistently, but the developer chooses the level based on the nature of the change . npm versionupdates three artifacts, not one. The version inpackage.json, the version inpackage-lock.json, and the Git tag are all updated from the same input. This consistency is the command’s primary value over manual editing .- The Git integration creates a commit and a tag. The commit message defaults to
vX.Y.Zand can be customized with-m. The tag is lightweight by default and can be GPG-signed withsign-git-tag=true. - Lifecycle scripts enforce the release process.
preversionblocks the bump if tests fail.versionbuilds and stages the distribution.postversionpushes the commit and tag. The order is fixed, and each script has access to the version state it needs . - Prerelease versions change the meaning of
patch. Apatchbump on1.2.0-5produces1.2.0, not1.2.1. The prerelease suffix is removed, and the patch number is not incremented. This is the one behavior that contradicts the standard increment logic .
Remember: npm version is a small command with a large responsibility. It is the step that converts a set of changes into a version number, a Git tag, and a commit that can be published and traced. The three levelsโpatch, minor, majorโare the vocabulary of that responsibility. The lifecycle scripts are the hooks that let the release process include tests, builds, and pushes without manual steps. When the command runs, it performs the operations in a fixed order, and each operation depends on the previous one succeeding. A failed test in preversion stops the bump. A failed build in version stops the commit. The command is designed to fail fast and leave the repository in a known state.
Stop using slow, ad-bloated tool sites! ๐คฎ
๐ Search “KandZ Tools” on Google to use many professional utilities for free.
KandZ.me is the ultimate minimalist hub for:
โ
Finance (Mortgage, Interest, Inflation)
โ
Tech (Base64, JSON, Dev Suite, IP)
โ
Health (BMI, BMR, TDEE)
โ
Productivity (Timer, Workspace, QR)
โก๏ธ Fast & Private
๐ No data leaves your device
๐ 100% Free
๐ Use it now: https://tools.kandz.me
๐ Bookmark itโyouโll need it later!