Design SystemsEngineering

How to version a design system without breaking things

Semantic versioning is the easy part. The hard part is what to do when your tokens change and a thousand consumers don't notice.

Every design system team eventually realizes that versioning is the part of the job they didn't budget time for. The semver decision is easy. What's hard is what happens after you publish the new version and find out that consumers either didn't update, updated and broke, or updated and didn't notice the visual changes that came with the upgrade.

The version number is a contract. The contract works only if the people on both sides understand what it means.

What major, minor, and patch should actually mean

Semantic versioning is well-documented for code APIs. For design systems, the rules are similar but need adjustment because design systems have visual contracts on top of API contracts.

A breaking change in a design system is anything that requires a consumer to do work to upgrade. Removing a prop, renaming a component, changing the default behavior of an existing variant. These are obvious major changes. Less obvious: changing the visual output of a component in a way that would require a consumer to adjust their layout. A button that gets 4px taller in a "minor" release will break alignment in dozens of places, even if no API surface changed.

The honest rule: if the upgrade requires the consumer to look at their code or their UI to verify nothing broke, it's a major change. Minor releases should be safe to install without checking. Patches should be safe to install in your sleep.

Most teams underbump. They release visual changes as minor because the API didn't change, and consumers get surprised. Overbumping is annoying. Underbumping erodes trust in the version number itself.

The deprecation path

When you do need to make a breaking change, the path should be predictable. Add the new thing first, mark the old thing as deprecated with a clear message and migration path, ship that as a minor release, let consumers migrate at their pace, then remove the old thing in a future major release.

The deprecation window matters. A two-week window means consumers will get caught off guard. A two-year window means deprecations stack up and nobody migrates until they have to. Three to six months is usually about right, depending on how big your consumer base is and how often they ship.

What gets skipped most often: the migration path. Telling someone "this is deprecated, use ButtonV2 instead" is half the message. The other half is what changes when they migrate. Which props moved, which defaults shifted, what the visual difference will be. Without that, consumers either don't migrate or migrate by trial and error.

Communicating versions to designers

Version numbers are an engineering convention. Designers using the Figma library don't see them the same way, and the library updates often don't align cleanly with code releases.

The Figma library needs its own version story. Either it follows the code versions exactly (and changelog entries reference both), or it has its own changelog that maps to code releases. The worst outcome is the silent divergence. Designers using a Figma version that doesn't match what's shipping in production, with no easy way to tell.

The cleanest setup I've seen: a single changelog that documents every change, marked with which surface (code, Figma, or both) it affected. Designers and engineers both check the same source. The version number is the same on both sides.

When to ship a major version

Major versions feel scary because they require consumers to do work. Teams avoid them, batch breaking changes into infrequent major releases, and end up shipping massive migrations that nobody wants to do.

The opposite approach works better: ship majors more often, with fewer changes per major. A major release with three breaking changes is a manageable migration. A major release with thirty is a project. Consumers will postpone the second one indefinitely, and you'll end up supporting the old major for years.

Get comfortable with the major version number being high. Tailwind is on v4. React Router is on v7. The number isn't a status symbol; it's a record of how many times you've asked consumers to do work. Asking more often, for smaller amounts of work, is more sustainable than asking rarely for a lot.

The change consumers care about most

Versioning gets the most attention from teams who are running their design system as a public package. Most internal design systems have a smaller consumer base and a tighter feedback loop, which makes versioning feel less critical.

It isn't. The internal version number is the only mechanism you have to coordinate when changes land and what consumers should expect. Without it, you're either pushing changes silently (and breaking things) or pushing changes loudly (and adding coordination overhead to every release). The version number absorbs that coordination so the team doesn't have to.

Greg Sargent
Greg SargentDirector of Design Systems, Spring Health

I write about design systems, accessibility, and the way AI is changing how we build software.

Published December 12, 2025

Be the first to rate this article.