Versioning
Good versioning communicates intent to consumers. It tells them whether an update is safe to adopt or requires migration work.
Semantic Versioning (semver)โ
npm uses Semantic Versioning: MAJOR.MINOR.PATCH
| Bump | When | Example |
|---|---|---|
| MAJOR | Breaking changes | 1.2.3 โ 2.0.0 |
| MINOR | New features, backward-compatible | 1.2.3 โ 1.3.0 |
| PATCH | Bug fixes, backward-compatible | 1.2.3 โ 1.2.4 |
When to bump whatโ
- MAJOR: Removed or renamed exports, changed function signatures, dropped Node.js version support
- MINOR: New exported functions, new optional parameters, new features
- PATCH: Bug fixes, performance improvements, documentation updates in code
Pre-release Versionsโ
Use pre-release identifiers for unstable versions:
1.0.0-alpha.1
1.0.0-beta.1
1.0.0-rc.1
Publish pre-releases under a dist-tag to avoid affecting latest:
npm publish --tag next
The npm version Commandโ
Bump versions directly from the command line:
npm version patch # 1.2.3 โ 1.2.4
npm version minor # 1.2.3 โ 1.3.0
npm version major # 1.2.3 โ 2.0.0
npm version prerelease --preid=beta # 1.2.3 โ 1.2.4-beta.0
This command:
- Updates
versioninpackage.json - Creates a git commit
- Creates a git tag (
v1.2.4)
Dist-tagsโ
Dist-tags are labels that point to specific versions:
| Tag | Purpose |
|---|---|
latest | Default install version (what npm install gets) |
next | Upcoming major/pre-release channel |
canary | Bleeding-edge builds from main branch |
# Publish to a specific tag
npm publish --tag next
# Install from a tag
npm install my-package@next
# Move a tag to a different version
npm dist-tag add my-package@2.0.0-rc.1 next
Conventional Commitsโ
Conventional Commits is a commit message format that enables automated versioning:
feat: add streaming support โ MINOR bump
fix: handle null input gracefully โ PATCH bump
feat!: redesign plugin API โ MAJOR bump
chore: update dev dependencies โ no release
docs: fix typo in README โ no release
The format is: type(optional scope): description
Common types: feat, fix, chore, docs, refactor, perf, test, ci
Automated Versioning Toolsโ
| Tool | Approach | Best for |
|---|---|---|
| Changesets | Developers add changeset files per PR | Monorepos, team workflows |
| semantic-release | Fully automated from commit messages | Single packages, CI-driven |
| release-it | Interactive prompts + automation | Flexible, single packages |
Changesetsโ
Changesets uses a file-based approach where developers declare version intent:
npx changeset # Create a changeset describing your change
npx changeset version # Consume changesets, bump versions
npx changeset publish # Publish to npm
semantic-releaseโ
semantic-release fully automates versioning based on commit messages. No manual intervention needed โ CI handles everything.
release-itโ
release-it provides an interactive CLI for releases with support for changelogs, git tags, and npm publishing.
Version Ranges for Consumersโ
When depending on packages, version ranges determine which updates are accepted:
| Range | Meaning | Example |
|---|---|---|
^1.2.3 | Compatible with 1.x.x (โฅ1.2.3, <2.0.0) | Default for npm install |
~1.2.3 | Patch-level changes (โฅ1.2.3, <1.3.0) | More conservative |
1.2.3 | Exact version only | Most restrictive |
For application projects, consider pinning exact versions and using tools like Dependabot or Renovate to manage updates. For libraries, use ^ ranges to allow flexibility for consumers.