Here's a scene worth sitting with. A designer needs a testimonial block for a landing page going live in 48 hours. She opens the Figma library and finds three options: Testimonial / Card / Compact, Testimonial / Card / Featured, and Testimonial / Quote / Large. Next to the third one, a comment thread from 74 days ago debates whether to deprecate it in favor of new flex-basis logic for right-to-left languages the product doesn't even support yet.
She picks one, ships the page, and moves on. But the system just got a little harder to trust.
That's how variant debt accumulates. Not through bad decisions — through reasonable ones, made one at a time, that nobody went back to audit.
The Proliferation Pattern Is Predictable
Variant explosion follows a consistent arc. A team ships a Button with primary and secondary variants. A product request comes in for a destructive action — add danger. Then a ghost button for low-emphasis contexts — add ghost. Then a small inline version for data tables — add compact. Then someone needs a loading state that works across all of them.
Each addition is defensible in isolation. The problem is that the system has no mechanism for asking whether the new variant is a permanent architectural decision or a one-time product need. Those are very different things, and treating them the same way is where the debt starts.
Codexical's audit work makes the economics of this concrete: a system with 400 components at 60% utilization is typically worth less than one with 120 components at 95% utilization, because every unused component still carries a monthly cost — framework update maintenance, onboarding confusion, and the near-duplicates that get built when developers can't tell if the old version still works. The ROI numbers that get cited for mature design systems (the Figma research puts it at 135–170% over five years) come from teams that kept that utilization ratio tight, not from teams that maximized library size.
Most teams track the numerator. Almost nobody tracks the denominator.
The Shadow System Is a Symptom, Not the Problem
When the cost of doing things correctly exceeds the cost of doing them locally, competent engineers will always choose local. That's not a character flaw — it's a rational response to a broken process.
The Tye and Tie piece on design systems as legacy code captures this precisely: a senior engineer needs 32px spacing where the token scale only offers 24px and 40px. To add the token, he'd need to draft a proposal, submit it to the design system guild, wait for a bi-weekly review, and get three stakeholders to agree. Instead, he writes a CSS override with a comment that says "temporary fix; will move to theme later." He never moves it to theme. Nobody does. The shadow system grows one margin-top at a time.
The variant problem is the same dynamic applied to components. When the governed path requires a PR, a review cycle, and a design system team sign-off, product teams will generate their own variants locally — and those variants will never make it back into the system. The Design Systems Collective piece on local-first workflows argues for exactly this distinction: a local component is a product-level experiment; a design system component is a governed decision. The mistake is conflating the two, either by blocking all local work (creating the bottleneck) or by promoting everything local into the system (creating the sprawl).
Auditing for Cost, Not Just Coverage
The fix isn't a stricter contribution process. Stricter gates just push more work into shadow systems. The fix is treating component existence as a standing liability rather than a one-time investment.
That means tracking utilization, not just adoption. It means having a deprecation path that's as well-defined as the contribution path. And it means asking, for every variant in the library: if we removed this tomorrow, who would notice, and what would they do instead?
The uxpilot.ai enterprise design systems piece cites a 2025 Design Systems Report finding that only 8% of teams describe their systems as "very stable" — which tracks, because stability requires active retirement of low-use components, not just active addition of new ones. The teams running mature systems treat the library like a product with a backlog, not a warehouse with infinite shelf space.
The practical version of this: schedule a quarterly utilization audit. Pull component usage data across your product surface. Any variant with near-zero usage in the last two quarters gets flagged for deprecation review — not automatic removal, but an explicit decision about whether it earns its maintenance cost. That decision forces the conversation that should have happened when the variant was added.
Variant debt is invisible by default. The teams that don't accumulate it aren't the ones with stricter contribution policies — they're the ones that built a balance sheet.
