Blog
4 min read

Semantic Versioning Explained: What 2.4.1 Actually Means

Version numbers like 2.4.1 follow a convention: major.minor.patch. What each number promises, what ^ and ~ mean in package.json, why '0.x' versions are different, how lock files fit in, and how to version your own app or library.

Open package.json and you'll see dependencies like "react": "^19.1.0" and "zod": "~3.24.2". Those numbers — and the little ^ and ~ in front — follow a convention called semantic versioning. Understanding it tells you which updates are safe and which might break your app.

Three numbers, three promises

A semantic version has three parts: MAJOR.MINOR.PATCH.

  2  .  4  .  1
  │     │     └── PATCH: bug fixes, nothing else
  │     └──────── MINOR: new features, nothing broken
  └────────────── MAJOR: breaking changes
  • PATCH (2.4.1 → 2.4.2) — bug fixes. Your code should work unchanged.
  • MINOR (2.4.1 → 2.5.0) — new features added in a backwards-compatible way. Your code should still work.
  • MAJOR (2.4.1 → 3.0.0) — something changed in a way that may break your code: a function removed, renamed, or behaving differently.

When a number goes up, the ones to its right reset to zero: 2.4.1 → 2.5.0 → 3.0.0.

The whole system is a promise from the library's authors. Most keep it well. Some don't — which is why tests and lock files still matter.

Versions before 1.0

Versions starting with 0 — like 0.8.3 — mean "still in early development." The usual promises are relaxed: in practice, a change in the minor number (0.8 → 0.9) may break things. Treat 0.x updates with care.

Pre-release tags

You'll also see versions like 3.0.0-beta.2 or 5.0.0-rc.1. These are pre-releases: test versions before the real release. Package managers don't install them unless you ask specifically.

^ and ~ in package.json

The symbol in front of a version tells your package manager which versions are acceptable when installing:

Written Allows Meaning
"19.1.0" exactly 19.1.0 Pinned
"~19.1.0" 19.1.x Patch updates only
"^19.1.0" 19.x.x Minor and patch updates (npm's default)
"*" or "latest" anything Risky — avoid

(For 0.x versions, ^ is more cautious: ^0.8.3 allows only 0.8.x.)

So "^19.1.0" says "any version 19 that's at least 19.1.0 is fine." That's why two people running npm install a month apart could, in principle, get different versions. (npm and package.json Explained.)

Lock files fix that

Your lock file — package-lock.json, pnpm-lock.yaml, or yarn.lock — records the exact version of every package that was installed, including dependencies of dependencies. Commit it. With it, everyone (including your server) installs the identical set.

  • npm install respects the lock file, updating it only if package.json changed.
  • npm ci installs exactly what the lock file says, and fails if it doesn't match — the right choice for servers and CI. (GitHub Actions CI Basics.)

Updating dependencies safely

Semantic versioning tells you how careful to be:

  • Patch and minor updates: usually safe. Update, run your tests, check the app.
  • Major updates: read the changelog or migration guide first. Update one major dependency at a time, on a branch, and test properly.
npm outdated        # what's behind, and by how much
npm update          # apply updates allowed by your ^ and ~ ranges

How to Update Dependencies Safely covers the full process.

A note on AI tools: models were trained on older versions of libraries and sometimes write code for a previous major version — calling functions that were renamed or removed. If an AI-written call fails with "is not a function," check which major version you have installed against which one the code assumes.

Versioning your own project

For an app that only you deploy, you don't strictly need version numbers — Git commits and deploy dates identify versions. But they help if you:

  • Publish a library or API others depend on — then follow semantic versioning carefully. Breaking your users' code in a minor release loses their trust.
  • Ship a mobile or desktop app — app stores require version numbers.
  • Want readable release notes — "what changed in 1.4?"

A changelog (CHANGELOG.md) listing what changed in each version is a kind thing to keep. (What Is Markdown?.) Some teams generate version numbers and changelogs automatically from commit messages written in a structured style. (How to Write Good Commit Messages.)

The summary

  • MAJOR.MINOR.PATCH — breaking, features, fixes.
  • 0.x — anything may change.
  • ^ allows minor updates; ~ allows patches only.
  • Commit your lock file; use npm ci on servers.
  • Read the changelog before a major update.

EasySpawn gives your projects a persistent server where Claude Code can update dependencies on a branch, run your tests, and show you what changed before anything reaches production. See how it works or join the waitlist.

Related: How to Update Dependencies Safely · npm and package.json Explained · npm Supply Chain Security

Keep reading