· 7 min read

Why most design systems quietly fail

Most design systems die not from lack of components, but from lack of trust, and the death is always quiet: no meeting, no announcement, just one more team quietly forking a button.

Design systems have a graveyard problem. Teams invest months building a shared library, ship it with fanfare, and then watch it quietly rot as product teams fork components the moment it can't keep up. I've seen it happen more than once, including on systems I built.

The failure is almost never technical. The tokens are fine. The components are fine. What breaks is the social contract: the implicit agreement that the system is worth the friction of following it.

Trust is the actual dependency

Trust erodes the first time a team waits two weeks for a component the system doesn't have. It erodes a second time when they submit a contribution and never hear back. By the third time, they've already built their own shadow library, and you've lost them.

What makes this hard to see from inside the system team is that nobody announces it. There is no meeting where a product team declares independence. There is a deadline, and a component that nearly fits, and a developer who copies it into the feature folder and changes two things. That copy is not a betrayal. Nobody puts on a villain cackle before copy-pasting a Button component. It is the cheapest correct decision available to someone with a date to hit.

Every one of those copies is a small, rational bet against you. The system's real health metric is how often that bet gets made, and almost nobody measures it.

The half-life of a fork

A forked component starts life identical to the original, which is why it looks harmless. Then the original gets a focus state, an accessibility fix, a change to how it handles long strings on a narrow screen. The fork gets none of that.

Six months later the two are genuinely different components with the same name, and the difference is invisible in every screenshot. This is where the cost lands: not in the duplication, which is cheap, but in the divergence, which is silent and compounding.

By the time anyone notices, the fix is no longer a merge. It is an audit.

Treat it like a product, not an infrastructure project

What I've found works: a real backlog, real prioritisation, and someone whose job is to feel the friction product teams feel. Not a platform team that ships components, a product team that ships leverage.

That reframing changes what you do on a Monday morning. An infrastructure team asks what is missing from the library. A product team asks who is currently blocked, and by what, and what would unblock the most people this week. Those two questions produce very different roadmaps, and only one of them tracks the thing that actually determines survival.

It also changes who you listen to. Infrastructure teams take requests from whoever is loudest, which in practice means whoever is most senior. Product teams go and watch. The most useful hour I have spent on any design system was sitting with a developer implementing a screen with it and saying nothing while they worked.

Your users are not the designers

The people who suffer most from a bad design system are engineers, and they are usually the last ones consulted about it.

A component can be perfect in the design file and miserable in code: fifteen props, three of which are mutually exclusive, and no way to do the one variation this screen needs without a wrapper. The designers are happy, adoption is falling, and nobody can explain why.

If your system has a design side and a code side, the code side is the product. The design side is the documentation.

Coverage matters more than quality

An unpopular position, but I hold it: a mediocre component that exists beats an excellent one that doesn't.

The reason is that partial coverage forces a decision on every screen. Is this thing in the system? Do I check first, or do I just build it? When the answer is "check first" often enough, checking becomes a habit. When the system covers half the surface, checking is a coin flip, and people stop flipping.

This is also why the long tail is worth more than it looks. Nobody writes a case study about shipping a date picker, an inline validation message and a table empty state, but those three are the ones a team hits at 4pm on a Thursday, and they are where forking starts.

The version nobody wants to hear

Some of the coverage problem is a scoping problem you created. A system that admits fifteen carefully governed components will be forked more than one that admits sixty rough ones, because governance is a cost paid by the people who most need to move fast.

Quality gates should scale with blast radius. A button used on every screen deserves scrutiny. A component two teams need and nobody else will touch does not need a design review board.

Make the wrong thing hard to type

Coverage gets you the pieces. What keeps them being used is that the alternative is inconvenient, and that is a tooling job rather than a documentation one.

This site enforces its own scale with a linter rule, and the rule is blunt: a literal colour, a literal font size, a literal weight, a spacing value above ten pixels or a radius above five are all refused, with an error message that names the token to use instead. It is not a style preference. It is the difference between "please use the tokens" in a README and a build that will not pass.

The effect shows up in a way I did not expect. Building the diagrams in these articles, I could not reach for a grey I liked, because the linter would not have it, so every one of them is made of the real tokens and every one follows the theme for free. The constraint did the design work. That is the version of a design system that survives: not the one with the best documentation, the one where doing it properly is the path of least resistance and doing it wrong takes a deliberate stylelint-disable and a sentence explaining yourself.

The message matters as much as the rule. A linter that says "unexpected value" teaches nobody anything. One that says "use a --space-* step instead of a bare 12px, and if no step fits, add one with a comment saying why" is documentation delivered at the exact moment somebody needed it.

Adoption is the metric, and it has to be visible

The components are the output. Adoption is the metric. The system only works when teams choose it because it makes their lives easier, not because an architect said so.

Making that measurable is worth the effort, and it is more tractable than it sounds. Percentage of rendered components coming from the system. Number of one-off styles per screen. How long a request sits before it is answered. None of these is perfect and all of them are better than counting how many components you have shipped, which measures your output and says nothing about anyone else's.

The number that changed the most conversations for me was time-to-answer on requests. Not time to ship the component: time to reply with a decision, including "no, and here is why". A fast no keeps a team inside the system. A slow silence sends them out of it, permanently.

Mandates buy compliance, not adoption

Every large organisation eventually reaches for a mandate. It works, in the narrow sense that usage goes up.

What it does not do is remove the friction that made people leave. It converts an adoption problem into a resentment problem, and resentment is harder to debug, because the people experiencing it stop telling you about it. They are following the rule. They are also routing around it in ways you will find out about much later.

Mandates are useful for one thing: holding a line that has already been won. They are terrible at winning one.

What I would do differently

Start smaller than feels responsible, and go deep on the parts a team actually assembles a screen out of rather than wide on a component inventory.

Ship the contribution path on day one, even if it is a shared channel and a promise to answer within two days. The path matters more than the process, and the promise matters more than the path.

Publish the roadmap and the no-list together, so a team can tell at a glance whether to wait or to build. Ambiguity is what produces forks. A clear no rarely does.

And measure the thing you are actually trying to cause. Not components published. Not tokens defined. The number of times someone chose the system when they did not have to, which is the only evidence that any of it was worth building.