Every team eventually ships Button, ButtonNew, PrimaryButton, and MarketingCTA that differ by two pixels and a shadow.
That is not flexibility. That is sprawl — and it taxes every future feature with decision fatigue, inconsistent accessibility, and endless one-off CSS. Design systems work when the default is reuse, and new primitives require a case.

Alignment is the product. Drift is the default without governance.
Why sprawl happens
- Deadlines reward “just copy the button and tweak”
- Designers invent visual variants without engineering review
- No ownership of deprecation
- Storybook exists but is not part of the definition of done
- Tokens are weak, so components absorb one-off values
Addition checklist
Before a new component or variant:
- Which user job is not met by existing primitives?
- Can tokens or props extend an existing component?
- Who owns accessibility and keyboard behavior?
- What is the deprecation plan for what it replaces?
- Is there a docs/Storybook entry in the same PR?
No answer → no merge.
Measure adoption
Track the percentage of UI using system components vs one-offs (even approximately via codemods or package imports). Celebrate deletions of variants. A healthy library shrinks sometimes.
API design for components
Prefer composition and variants over parallel components:
Buttonwithvariantandsizebeats four near-copies- Document do/don’t examples
- Forbid styling hacks that pierce encapsulation for “just this page”
Closing
Treat the library like a product with a ruthless editor. Fifteen buttons is not a system; it is a junk drawer with TypeScript types.
Need design system governance? Start a project inquiry.
Contribution model
- RFC for new components above a complexity threshold
- Office hours for “should this be a variant?”
- Design + eng co-ownership of the release train
Breaking changes
Semver the library. Provide codemods for renames when you can. Never silently change accessibility behavior in a patch.
The “marketing exception”
Marketing will always want a one-off. Channel it: temporary local composition using public primitives, or a time-boxed experiment component with a delete date. Never permanent forks without review.
Visual QA
Chromatic/Storybook visual tests catch accidental variant drift. Wire them to the packages that power production, not a toy Storybook that diverges.
Discovery questions we ask
- What breaks if this is wrong in production next week?
- Who is paged, and is that written down?
- What does “done” mean in a checklist a stranger can run?
- Which metric proves the practice is working a month later?
If those answers are vague, the write-up is not finished — and neither is the system.
How this fits the rest of the journal
Pair this note with post-launch ownership, performance budgets, and technical SEO where relevant. Most failures are cross-cutting: a migration without redirects, a flag without expiry, a form without rate limits.
Closing reminder
Write the operating rules while the team that built the feature still remembers why. That is cheaper than reverse-engineering six months later during an outage.