Versions and dependencies

Use semantic versioning

Connect major, minor, and patch releases to the compatibility promise made to consumers.

Semantic versioning (semver) tells consumers what kind of upgrade they are getting. The version number is not marketing. It is a compatibility promise about your documented public API.

A semver version looks like MAJOR.MINOR.PATCH, for example 1.4.2:

  • Patch (1.4.21.4.3): bug fixes only. Same API, same behavior for valid inputs.
  • Minor (1.4.21.5.0): backward-compatible additions. New options, new exports, faster internals.
  • Major (1.4.22.0.0): breaking changes. Removed exports, changed error types, different defaults.

Classify changes from the consumer’s view

Think about @acme/slugify-title at 1.2.0:

ChangeBumpWhy
Fix double hyphens for "foo--bar"patchSame function signature, corrected output
Add optional { locale: 'de' }minorOld calls still work unchanged
Rename slugifyTitle to toSlugmajorImport path or name breaks existing code
Throw on empty string where you previously returned ''majorCallers that relied on the old behavior break

Notice the last row. A “small” internal change can still be major if documented behavior shifts.

Record breaking work before you pick the number

When you plan a major release, list every breaking change in the changelog before you bump package.json. Consumers use that list to estimate migration time.

npm version patch
npm version minor
npm version major

Each command updates package.json, creates a git tag if you are in a git repo, and refuses to run on a dirty working tree by default.

Do not mix signals

I never pick version numbers from calendar dates, sprint numbers, or “this felt big.” If you use a different scheme, say so loudly in the README. Otherwise people will assume semver and upgrade at the wrong time.

For 0.x versions, semver treats minor bumps as potentially breaking. Stay on 0.x while the API is still moving, then cut 1.0.0 when you are ready to honor the semver contract.

Lesson completed