A Figma library and a folder of buttons will get applause in a kickoff. They will not survive the second product team that is late. That team will copy what it needs, rename it, and move on. Six months later the platform has three primary buttons, and none of them agree on focus, loading, or what happens when the label is a full sentence.
The outcome is predictable once you look at what was actually shipped. A kit can be copied. Infrastructure is what other work depends on, so going around it costs more than using it. A design system earns that status when changing a decision once changes it everywhere it should.
Tokens are the public API
Color, type, space, radius, elevation, motion. When those decisions live as raw values inside feature code, every screen is a fork. A token is a name for a decision you intend to keep. --color-text-danger can move to a more accessible red without a hunt through the repo. A hex code cannot.
Semantic names matter more than a pretty palette. A product should ask for accent, danger, and surface. It should not ask for indigo 600. The palette can change underneath a meaning that stays put. Treat the set like an API: adding a token is cheap, renaming one is a migration, and a one-off token published because a mock was “close enough” is a breaking change you have agreed to maintain.
Propagation
Components are contracts
A component is finished when its states are named and its escape hatches are deliberate. Disabled, loading, error, empty, overflow. Keyboard behavior, focus, and the accessible name. What a caller may pass, and what they may not.
An open className feels helpful until it becomes the real API. Every override is a decision the system declined to make, now copied at every call site. Composition outlives configuration. A button with a few variants and a slot will still make sense after the fifth product. A button with thirty booleans and a style object “just in case” becomes a second design tool that nobody owns.
Documentation belongs in the release, beside the code. A component without a usage rule is a suggestion. Suggestions are the first thing a deadline deletes, which means they were never really there.
Adoption is a path
Teams adopt a system when the shared path is faster than the local one. Inspiration at the kickoff does not survive the week the milestone slips.
- Wire tokens, type, and primitives into the app generator so a new app is already on the system.
- Fail the build when a raw color lands in a feature package.
- Ship a codemod with every breaking change, so a major version arrives as a pull request.
The moment a migration is optional and manual, teams pin the old version. You are then maintaining two systems, and the Storybook still looks healthy. That is the quiet way design systems die.
Fewer components, a stricter release
The catalog wants to grow. Every request feels like proof that the system matters. Most requests are proof that a composition pattern was never written down. Ship the release with the same care as the button: a changelog, a version, a migration, and visual regression on the primitives other apps actually render.
The signal I watch for is small. When someone on a product team asks which gray to use, the system is still a kit to them. When they stop asking, it has become infrastructure.
Change a decision once. That is the whole product.
