Have you ever opened your package.json
and wondered what all those numbers and symbols mean? Something like this might look familiar:
"react": "^17.0.2"
At first glance, it might seem like just a version number but there’s more happening here than meets the eye.
Those three numbers (17.0.2
) follow a rule called Semantic Versioning, which tells you whether an update includes a small bug fix, a new feature, or a breaking change.
And what about the symbols like ^
or ~
in front of the version number? They’re just as important they control how npm decides which versions to install when you run npm install
.
In this article, we’ll explore:
- What each part of a version number means (
major.minor.patch
) - When to bump each version correctly
- How to use
^
,~
, and exact versions to manage dependency updates safely
By the end, you’ll know exactly what each number and symbol means and how to keep your project dependencies both stable and up to date.
What Is Semantic Versioning?
npm follows a system called Semantic Versioning (SemVer), where version numbers are divided into three parts separated by dots:
major.minor.patch
Using the react example ("react": "^17.0.2"):
-
Major version:
17
-
Minor version:
0
-
Patch version:
2
Each part has a specific purpose in describing how the package has changed.
Patch Version
The patch number increases when backward-compatible bug fixes are released.
✅ When to bump the patch:
- Fixing small bugs
- Patching security issues
- Making internal improvements that don’t change the API
Example:
Before:
import { sumNumbers } from 'my-package';
After a patch update, the internal behavior of sumNumbers
might be improved but the way you use it stays the same.
Minor Version
The minor number increases when new features are added in a backward-compatible way.
✅ When to bump the minor:
- Adding new functions or options
- Improving performance
- Enhancing features without breaking existing code
Example:
Before:
import { sumNumbers } from 'my-package';
After a minor update:
import { sumNumbers, subtractNumbers } from 'my-package';
You gain a new feature (subtractNumbers
), while existing code remains functional.
Major Version
The major number increases when breaking changes are introduced.
⚠️ When to bump the major:
- Removing or renaming functions
- Changing APIs or arguments
- Modifying behavior in a way that requires updates to your code
Example:
Before:
import { sumNumbers } from 'my-package';
After a major update:
import { addNumbers } from 'my-package';
Since the function name changed, users must modify their code signaling a breaking change.
Version Operators in npm
When declaring dependencies in package.json
, symbols like ^
, ~
, or no symbol define how npm handles version updates.
Caret (^
)
Allows updates that do not change the leftmost non-zero version number typically minor and patch updates.
Example:
^4.13.6
✅ Can update to: 4.14.0
, 4.99.9
❌ Cannot update to: 5.0.0
Use case: Great balance between stability and receiving improvements.
Tilde (~
)
Allows updates to the patch version only, within the specified minor version.
Example:
~4.13.6
✅ Can update to: 4.13.7
, 4.13.9
❌ Cannot update to: 4.14.0
Use case: Ideal when you want to lock features but still get bug fixes.
Exact Version (no symbol)
Locks the dependency to one specific version.
Example:
4.13.6
✅ Always installs exactly version 4.13.6
❌ Will not update automatically
Use case: Maximum stability perfect for production-critical systems.
Summary
Symbol | Allows Updates To | Typical Use Case |
---|---|---|
^ |
Minor and patch versions (same major) | Accepts new features and fixes safely |
~ |
Patch versions only (same minor) | Prioritizes stability with small updates |
Exact | No updates | Ensures total consistency |
In short:
Semantic versioning helps you understand what changed, while version operators control how updates happen. Together, they form the foundation of predictable and maintainable dependency management in npm.
Top comments (0)