Design SystemsWriting

Designing UI Primitives That Scale

Why strong primitives do more than tidy up a component library; they shape how products scale across teams and platforms.

Nov 25, 2025
3 min read
Aadarsh Srivastava

Primitives are leverage

Most UI systems don't fail because of sloppy styling or inconsistent spacing. They fail because the primitives are too specific.
When a primitive encodes a product concept instead of a capability, the system stops bending. Every new requirement forces either duplication or an exception, and the UI layer slowly turns into a graveyard of one-off components. Strong primitives are boring by design, and that's exactly why they last.

What makes a good primitive

A good primitive is reusable: it appears in different contexts without modification. It's composable: it gains meaning when combined with other primitives, not on its own. And it's context-agnostic: it doesn't know or care why it's being used.
A primitive should describe what something is, not why it exists. The moment it starts answering product questions, it stops being a primitive.

The cost of specificity

Specific primitives feel productive at first. They move fast, they read well in a diff. Then they lock you in.
Names like HomeHeroCard, TrendingDestinationTile, or PromoBannerV3 bake placement, intent, and version into the component itself. All three of those things change eventually, and when they do, the primitive becomes either misleading or dead weight. Specificity ages badly.

Boring primitives win

Good primitives are deliberately generic: Card, Media, Title, Action, Badge. Alone, each one looks underwhelming. Put together, they say something.
Meaning comes from composition, not from a special-purpose component. A "Trending Destination" isn't a primitive. It's a Card with Media, a Title, a couple of Badges, and an Action. If the concept changes tomorrow, none of the underlying pieces need to move.

Primitives enable everything else

Once the primitive layer is solid, a lot of higher-level work falls out for free. Server-driven UI becomes possible because primitives form a stable rendering vocabulary. Cross-platform rendering works because primitives map cleanly onto platform-specific views. Agent-driven interfaces work because an agent can reason in primitives instead of screens. Experimentation gets cheap because composition changes without touching infrastructure.
None of that is a design-system concern. It's infrastructure.

Evolution without rewrites

Good primitive systems are asymmetric: primitives change slowly, composition changes fast. That asymmetry is the point. When primitives are stable, experiments stay cheap, features evolve without a rewrite, and old layouts can sit next to new ones without conflict.
Most UI rewrites don't happen because the design changed. They happen because the primitives were too specific to survive the change in the first place.

Designing for longevity

If you find yourself reaching for V2, New, or Updated in a primitive's name, that's usually a sign the abstraction underneath it is wrong. A primitive should be minimal, predictable, and hard to misuse. If it's easy to misuse, it's probably doing too much.