Most design system efforts begin the same way: someone audits the product, finds dozens of inconsistent buttons, and proposes a clean, unified component library. The library gets built. Six months later, half the product still uses the old buttons, and a new set of inconsistencies has appeared in the gaps the system didn't cover.
The failure isn't in the components. It's in treating the system as a deliverable instead of a relationship — between design and the codebase that has to actually use it.
A design system built in isolation from the existing codebase is asking engineering to do two jobs at once: ship features, and migrate to a new foundation. Under deadline pressure, the migration loses, every time — not because anyone disagrees with it, but because it's never the most urgent thing.
The systems that stick are usually the ones built as a layer on top of what already exists — new tokens that map onto variables already in use, new components that can be adopted one screen at a time, not a parallel universe that has to be migrated to wholesale.
A component library with no usage guidance just becomes a second place inconsistency can happen — now there are two button styles in the library itself, and no record of which one is current.
The documentation that actually gets read is short, opinionated, and answers the question someone has in the moment: which of these do I use, and why. Not a complete reference nobody opens until something's already gone wrong.
None of this is about the components being better-designed. It's about removing every reason not to use them.