Two years ago I shipped a token rename on a Friday afternoon. color-brand-primary became color-surface-brand in our system, a five-minute find-and-replace in our own repo. Monday morning, three product teams had failing builds, and not one of them had seen it coming, because there wasn't a changelog entry to see.
TL;DR: Design token adoption hit 84 percent of teams in 2026, up from 56 percent a year earlier (zeroheight - Design Systems Report 2026, 2026), but only 40 percent run any real token pipeline. Most still hand-sync tokens between design, docs, and code, which is exactly where breaking changes slip through unannounced.
Who Actually Owns the Design System?
Every versioning rule below answers to this question first, and most teams never write the answer down. Who gets to say no to a change? If the honest answer is "whoever opened the PR", you don't have governance, you have a shared folder with a changelog.
Three ownership models show up in practice, and they scale differently.
| Model | Who decides | Works when | Fails when |
|---|---|---|---|
| Centralized | a dedicated systems team | 3+ product teams consume it | the team becomes a queue everyone waits behind |
| Federated | contributors from each product team, shared review | contributors are senior and few | nobody owns the no, so the system sprawls |
| Hybrid | small core owns the API, product teams contribute | most mid-size orgs | the boundary is never written down |
Centralized is the model people picture, and it's the one that quietly turns into a bottleneck. A systems team of two serving six product teams will be the reason a launch slips, and the product teams respond by forking components locally. That fork is how a design system dies, and it dies looking healthy: the repo is fine, nobody uses it.
Federated sounds fairer and is harder than it looks. Shared ownership works right up to the first genuine disagreement about a component API, at which point somebody has to decide, and in a flat model that somebody doesn't exist. What you get instead is three variants of the same button, each justified.
I'd run hybrid for almost any team over about fifteen engineers, and the part that makes it work is boring to write and easy to skip: put in the repo, in words, which surfaces the core owns and which are open to contribution. Tokens and component APIs owned by the core. Documentation, examples and new component proposals open to everyone. When the boundary is written, a rejected PR is a rule doing its job rather than a person being difficult.
One thing to decide alongside it: does the owning team version on its own schedule, or does it ship when consumers need it? Own the schedule. A design system that releases on demand is a support desk, and the version numbers stop meaning anything within a quarter.
How Do You Decide What Counts as a Breaking Change?
Start with the consumer's code, not your own diff. If a product team upgrades and their existing implementation, unchanged, now renders or behaves differently, that's major. Renaming a token, removing a component export, flipping a default, or changing what a prop does all qualify, even when the change looks trivial in your own PR. Adding a new token, a new variant, or an optional prop with a backward-compatible default is minor. Bug fixes that don't touch the API are patch.
Visual changes deserve their own scrutiny here. A spacing token that shifts by 2px feels like a patch to the person who made it and a layout bug to the six teams whose padding just moved. I'd argue visual drift inside a shared token is major far more often than teams admit, because it fails silently instead of throwing a build error.
A change that looks small in your diff can still be a major version to everyone downstream. Version the consumer's experience, not your own effort.
| Bump | Test | Example |
|---|---|---|
| Major | Consumer's unchanged code now behaves or renders differently | Renaming a token, removing a component export, flipping a default |
| Minor | Adds something new without touching what exists | A new button variant, an optional prop with a safe default |
| Patch | Fixes a bug without changing the API surface | Bug fix, no API change |
Should Tokens and Components Version Separately?
Yes, once your system serves more than one or two consuming teams. A design system isn't really one package. It's a graph: primitives, semantic tokens, components, and framework adapters, all moving at different speeds. Forcing them onto a single version number means an unrelated token tweak drags a major bump through every component, and consumers stop trusting your major releases because half of them weren't really breaking anything they used.
Changesets handles this well in a monorepo: each package gets its own version, and a single pull request can declare "patch for tokens, major for button" in one changeset file. Independent versioning means the changelog for @yourds/tokens only lists what actually changed in tokens, which is what your token-only consumers should read. Nobody wants to scroll through forty component entries to find the one line that affects them.
What Belongs in a Design System Changelog?
Four things, in every entry: what changed, why, who's affected, and what to do next. "Removed Button size='xl'" is a fact nobody can act on. "Removed Button size='xl', use size='large'; grep for size= props on Button" is a fact someone can paste into a terminal. Group entries by Major, Minor, and Patch under each dated version, and resist the urge to write clever release notes. Isn't the whole point of a changelog to save someone a debugging session at the worst possible hour?
Communicating a breaking change well is its own skill, not that different from the discipline behind a clean designer to developer handoff: name the intent, not just the diff, and don't make the reader reconstruct your reasoning from a Git log.
How Long Should a Deprecation Window Last?
Long enough for your slowest team to actually schedule the work, which in practice means at least one full quarter for anything widely used. My rule: a deprecated piece stays functional, with a warning, for two minor releases minimum before a major release removes it. Announce the deprecation the day you decide it, not the day you ship the removal. Give people a migration path in the same message, a codemod if you can manage one, a find-and-replace pattern if you can't.
I've watched a team announce and remove a component in the same release, and it produced exactly the fire drill you'd expect. A short deprecation window doesn't save you time. It just moves the pain onto someone else's sprint, usually the team least equipped to absorb it that week.
How Do You Get Teams to Actually Upgrade?
Publishing 3.0 and announcing it in a channel is a release. It isn't an upgrade. The system team owns the first, and the second only happens when upgrading costs less than staying put. Your consumers also live in two places, so there are two surfaces to work.
In code, let a bot carry the notice. Renovate can fold minor and patch updates into one pull request that merges on its own, and open every major as a separate PR that waits for a person, using matchUpdateTypes and groupName inside packageRules. Switch on its dependencyDashboard and each consuming repo gets one issue listing which design system versions are pending. That issue is your adoption chart, no survey required. It also exposes the repos that let majors pile up, which is uncomfortable and exactly the point. Pair each major with a codemod whenever the change is mechanical. jscodeshift is the usual toolkit, and a codemod that renames a prop across a repo turns a deprecation window from a to-do item into a command.
In Figma, the update isn't automatic either. Publishing a library prompts you for a description, and consumers see a blue badge on the library icon, then that description when they review and accept the update. It's the changelog designers actually read, and it's the field most teams fill with the word "updates". Write it the way you'd write the code entry: what changed, who's affected, what to do next.
Then measure lag instead of releases. The number worth tracking is how many consuming apps still sit on the previous major at the end of each quarter. If it doesn't fall during your deprecation window, either the window is too short or the codemod doesn't exist, and a longer announcement won't fix either one. The docs side, where stories and release notes sit together, is in the Storybook setup guide for design systems.
Which Tools Actually Automate This So You Don't Forget?
Changesets and semantic-release both solve the same core problem: humans forget to bump versions and write changelogs consistently, so let a tool enforce it from the commit or the PR. Changesets asks contributors to describe intent in a small file alongside their PR; a bot then computes the version bump and drafts the changelog entry from that description. Semantic-release goes further and infers the bump from commit message conventions, no manual file required, which works well if your team already writes disciplined conventional commits.
Neither tool fixes a team that doesn't think about breaking changes in the first place. The zeroheight data on token pipelines backs this up: with only 40 percent of teams running any pipeline at all, most breaking changes are still caught by a human noticing a broken build, not by tooling. Automate the mechanical part, version numbers and changelog formatting, but the judgment call of what's breaking still belongs to a person who understands the consumers.
Governance isn't a document you write once. It's the muscle of treating every token or component change as something a stranger on another team will read about before their build breaks, not after.