Design systems are usually launched well and maintained badly. Year one produces a component library and a documentation site; year two produces three forks, a component nobody can safely change, and product teams quietly building their own buttons again. The failure is rarely in the design - it is in versioning, adoption measurement and the absence of a deprecation path.
01Adoption is a number, and most teams do not have it
Ask how adoption is going and you will usually get an anecdote. The measurable version is straightforward: what percentage of rendered UI comes from system components rather than bespoke ones, per application, tracked over time. Static analysis of imports gives a decent proxy in an afternoon, and runtime instrumentation gives a better one.
Without that number the system is steered by whoever complains loudest. With it, you can see that one application is at eighty percent and another at fifteen, ask why, and usually find a specific blocker - a missing variant, a bundle size concern, a component that cannot be composed the way that team needs. That is actionable in a way that a general adoption push is not.
- Track adoption per application and per component, not as one figure.
- Instrument which components render in production, not just which are imported.
- Log which props are actually used - it tells you what to keep and what to cut.
- Treat a low-adoption application as a research subject, not a compliance problem.
02The components nobody uses are a cost, not a menu
Every mature system carries components built for one team that never generalised, and variants added to close a debate rather than to serve a use case. They still have to be tested, documented, kept accessible and migrated on every breaking change, and they inflate the surface area that makes the system feel heavy to newcomers.
Usage data resolves this without argument. A component with two consumers and a hundred lines of edge-case handling belongs in the consuming application, not in the shared library. Cutting it is a net gain even though somebody loses something, and doing it regularly is what stops the library from calcifying.
| Signal | Likely meaning | Action |
|---|---|---|
| High usage, high override rate | API too rigid for real needs | Add composition, not another prop |
| High usage, low override rate | Working as intended | Protect it; change it carefully |
| Low usage, recently added | Not discovered yet | Improve docs and examples first |
| Low usage, over a year old | Solves a problem one team had | Move it into that application |
| Forked in three or more repos | System version blocks a real need | Fix upstream urgently |
03Versioning: the breaking change you cannot avoid
A design system will need breaking changes - a token renamed, a prop removed, an accessibility fix that alters markup. Pretending otherwise produces the worst outcome: endless additive props, three ways to do the same thing, and components whose implementation nobody dares touch.
Publish semantic versions and mean them. Give consumers a deprecation window measured in months rather than sprints, keep the old path working with a console warning throughout, and ship a codemod with the release for anything mechanical. A migration that is one command is adopted; a migration that is a documentation page and goodwill is not.
04Tokens are the contract; components are the convenience
Components will be bypassed - a team needs a layout the system does not cover, or a one-off marketing page. Tokens will not be, because they are the cheap path to looking consistent. A system whose colour, spacing, typography and radius values are exported as tokens keeps visual coherence even where the components lost.
This shapes the investment order. Get the token layer right and stable first, keep it small enough to hold in your head, and name tokens semantically - surface, border-strong, text-muted - rather than by appearance. Tokens named blue-500 hardcode a decision you will want to change during a rebrand, and every consumer inherits the hardcoding.
05Component APIs that do not collapse into prop soup
The common failure is a component that accumulates props until it has thirty booleans and internal logic nobody can reason about. It happens one reasonable request at a time, and each addition is individually defensible.
The alternative is composition. Expose the pieces - a card with a header, body and footer slot - so teams assemble what they need without you predicting it. Reserve props for genuine variants that carry meaning, and be strict about that boundary. When you find yourself adding a prop that only exists to alter layout in one place, the real answer is almost always a composable sub-component.
- Prefer composition slots over configuration flags.
- Props should express intent (variant="danger"), not appearance (borderRed).
- Forward refs and unknown props - teams will always need an escape hatch.
- A sanctioned escape hatch prevents a fork; refusing one guarantees it.
06Governance that is a service, not a gate
Design systems staffed as a review board become a bottleneck, and bottlenecks get routed around. The teams that survive treat the system as a product with users: a clear intake path, a published roadmap, response times people can plan around, and contribution guidelines that make it realistic for a product engineer to add a variant themselves.
Fund it as ongoing product work, not as a project that completes. A system with no dedicated maintainer decays within two quarters - dependencies drift, accessibility regressions accumulate, and the documentation stops matching the code. At that point teams stop trusting it, and rebuilding trust costs more than the maintenance would have.
Topics
Lena Voss
Lead Architect · SyncTrix
Writes about the engineering decisions behind production systems - architecture, delivery and the trade-offs that only show up at scale.
Building something like this?
SyncTrix engineers AI, SaaS, platform and cloud systems for enterprises and high-growth teams. Tell us what you're shipping and we'll scope it with you.