skip to content

In a component library that follows semantic versioning, which version part should change for a new variant, a spacing bug fix, and a renamed property?

level: juniorimportance: must knowfreq 55%

answer

  1. what the consumer's code must change
  2. new capability versus broken promise
  3. bug fix restores documented behavior
  4. the old name stops working
  5. deprecated alias defers the major

basics

~10 s

A new variant is MINOR because it adds backward-compatible capability; a spacing fix back to the documented design is PATCH; a renamed property is MAJOR, because code still passing the old name stops working.

solid answer

~40 s

Semantic versioning ties each number to what happened to the library's declared public API. A new `variant` value adds backward-compatible functionality, so it is a MINOR. Fixing padding that drifted from the documented spec is a backward-compatible bug fix, so it is a PATCH. Renaming a property removes the old name, so every consumer still passing it breaks: that is a MAJOR. The rename can be softened - keep the old name working as a deprecated alias in a MINOR, then delete it in the next MAJOR. The test I apply to every change is: can a consuming team upgrade without editing their code and still get everything they were promised?

go deeper

for a junior

Recall the three meanings: PATCH fixes, MINOR adds or deprecates, MAJOR breaks. Classify each change by asking whether a consumer's existing code still works unchanged.

for a middle

Explain why a new required property is breaking while a new optional one is not, and show the alias-then-remove sequence that turns a rename into a MINOR plus a later MAJOR.

for a senior

Show that a component's public API includes defaults and documented behavior, and that a fix many consumers relied on may deserve a louder version signal than a PATCH.

for a principal

Frame the version number as a trust contract: one mislabeled release teaches dozens of teams to pin and stop upgrading, which costs more than the major you avoided.

## What the three numbers promise **Semantic versioning** writes a version as `MAJOR.MINOR.PATCH`. The specification only works once a package has **declared a public API** - in code, in documentation, or both - because every rule is phrased in terms of what happened to that API: - **PATCH** - only backward-compatible bug fixes. The spec defines a bug fix as an internal change that fixes incorrect behavior. - **MINOR** - new backward-compatible functionality is added to the public API, or some part of it is marked deprecated. - **MAJOR** - any backward-incompatible change to the public API. For a **component library** - the coded buttons, cards, steppers and dialogs that many product teams install - the public API is wider than a list of functions. It is the properties each component accepts, their allowed values and defaults, the events it emits, and the behavior and styling hooks it documents as stable. The consumer is a product team that wants to upgrade without reading every diff, whether its app is on the web or on native mobile. ## Classifying the three changes Take a food-delivery app's shared library and three pending changes: | Change | What an existing consumer sees | Bump | |---|---|---| | A new `outline` value for the restaurant card's `variant` property | Nothing, unless they opt in | MINOR | | Card padding had drifted from the documented spec and is fixed | The documented look they were already promised | PATCH | | `isVeg` renamed to `dietaryTag` | Their code still passes `isVeg`, which now does nothing or fails to type-check | MAJOR | The first adds a capability nobody is forced to use. The second restores behavior the library had already promised, so existing consumers get what they were owed. The third takes something away: code that was correct yesterday is wrong today. ## Softening a rename A rename does not have to arrive as a MAJOR on day one. The usual sequence: 1. In a **MINOR**, add the new name and keep the old one working as an alias, marked deprecated in the documentation and, where the platform allows, with a development-time warning. 2. Record both names in the change entry so consumers can migrate at their own pace. 3. In the next **MAJOR**, remove the old name. The specification's FAQ recommends that at least one minor release carry a deprecation before the removal lands in a major. How long the alias lives, and whether an automated code transform ships with it, is a governance policy decision rather than a versioning rule. ## Edge cases that trip people up - **A new required property is MAJOR**, not MINOR: every existing call site lacks it. A new *optional* property whose default preserves today's behavior is MINOR. - **A bug fix that someone relied on** is still, strictly, a PATCH. But if a large audience depends on the buggy behavior, the FAQ says to use judgment and let the version number warn them. - **Visual fixes can still surprise.** A padding fix that moves pixels will fail a consumer's screenshot baseline. That does not make it breaking when it restores the documented design, but the change entry should say what moved. A *deliberate* change to size or spacing that shifts consumer layouts is a different matter and many teams treat it as breaking. - **Major version zero** (`0.y.z`) is initial development: the spec says anything may change at any time and the API should not be considered stable. A library many teams ship to production should already be at 1.0.0. - **Released versions are immutable.** A mistake is corrected by a new release, never by republishing the same number with different content. ## A decision procedure 1. Would an existing consumer have to change code, or silently get behavior they were not promised? If yes, **MAJOR**. 2. Otherwise, does the release add something to the public API, or deprecate something? If yes, **MINOR**. 3. Otherwise, it restores documented behavior or changes internals only: **PATCH**. The number is a message to consumers who upgrade without reading the diff. Getting it right is what lets product teams trust automatic minor and patch upgrades; getting it wrong even once teaches them to pin every version and stop upgrading, which is far more expensive for the system than the major release that was avoided.

  • Is adding a new optional property always a MINOR release?
    Only when its default reproduces today's behavior exactly. If the new property defaults to something that changes how existing call sites render or behave, consumers who never pass it see a difference, and that is a breaking change. Either give it a default that preserves the old behavior, or ship it in a MAJOR.
  • Why should a component library used in production not stay on 0.y.z?
    Under semantic versioning, 0.y.z is initial development: anything may change at any time and the public API should not be considered stable. Staying there removes the signal consumers rely on, so every upgrade becomes a manual review. The specification's FAQ says that software used in production should probably already be 1.0.0.
  • A PATCH fix changes a card's rendered height by four pixels. Should the change entry mention it?
    Yes. It is still a PATCH if it restores the documented design, but consumers with screenshot baselines or tight layouts will see a difference. Naming what moved lets them approve a new baseline in minutes instead of debugging a mysterious failure after an upgrade they assumed was invisible.

saying these in an interview costs you the question

  • Adding a new required property is a MINOR because it adds functionality.
  • Renaming a property is fine in a MINOR since the feature still exists.
  • Any change that moves pixels must ship as a MAJOR release.
  • A mistaken release is fixed by republishing the same version number.
  • Version numbers are cosmetic; consumers should read every diff anyway.