Every design system eventually produces the same conversation. A product team needs something slightly outside the system's boundaries. The design system team says no. The product team ships it anyway, in a one-off file that never gets reconciled. Six months later, you have two button variants that are 2px apart in border-radius and nobody remembers why either exists.
The instinct to hold the line is correct. The execution is usually wrong.
The real failure isn't that teams break the rules. It's that most design systems have no principled way to break them — so every exception becomes either a bureaucratic standoff or untracked drift. As Miro's governance research describes it, fragmented experiences rarely start as a design problem. They start as a growth problem: teams move fast, decisions get made locally, and the gap between what's in the system and what's in production quietly widens.
The question isn't whether your system will get broken. It's whether the breaks are legible.
Consistency Has a Compounding Cost
The case for strict consistency is real. Shared components mean less CSS written per feature, fewer accessibility regressions, faster onboarding. The "Lego" model — described by Cristiano Rastelli in his analysis of design system impact — works when teams can assemble existing pieces without writing new primitives from scratch.
But consistency has a compounding cost that's easy to miss at the component level: it creates review bottlenecks. When one or two people become the arbiters of what's in-system and what isn't, the queue grows faster than they can clear it. Miro's governance research identifies this as one of the most common failure modes — teams start routing around the bottleneck, which means exceptions happen anyway, just without any record of the decision.
The irony is that over-enforcing consistency produces the inconsistency it's trying to prevent. You just can't see it because it's living in one-off Figma frames and hardcoded values rather than the component library.
Two Kinds of Rule-Breaking, Only One of Which Is Acceptable
I'd argue there's a clean distinction between exceptions that should exist and exceptions that shouldn't — and most teams conflate them.
Sanctioned exceptions are cases where the system genuinely doesn't fit the use case, the team has identified why, and the deviation is tracked. A data-dense internal tool that needs tighter spacing than the consumer product's comfortable defaults. A marketing page that needs a one-time hero treatment that would be noise in the component library. These aren't failures of discipline — they're the system doing its job, which is to serve product velocity, not to be complete.
Unsanctioned drift is what happens when the exception process is too slow or too opaque, so teams stop asking. An engineer hardcodes a color from memory. A contractor builds a component that already exists because they couldn't find it. Muzli's analysis of design system maintenance puts it plainly: bad naming creates hesitation, hesitation slows decisions, and slow decisions kill consistency. The system's own friction becomes the reason teams route around it.
The difference between these two categories isn't the deviation itself — it's whether anyone made a conscious decision.
// Sanctioned exception — documented at the component level
// DS-EXCEPTION: marketing/hero only
// Reason: one-time brand campaign, not for product UI
// Approved: 2024-01-15, revisit Q2
const HeroHeading = styled(Heading)`
font-size: 96px; /* outside type scale */
letter-spacing: -0.04em;
`;
// Unsanctioned drift — no context, no owner
const weirdButton = {
borderRadius: '6px', // system default is 4px, nobody knows why this changed
padding: '10px 18px',
};
The first is a design decision. The second is a mystery that will outlive everyone who was in the room.
The Heuristic: Make Exceptions Expensive to Create, Cheap to Track
If your exception process requires a design system team review, a Jira ticket, and a two-week wait, teams will skip it. If your exception process is a comment in the code and a line in a shared doc, teams will use it.
The goal isn't to prevent exceptions. It's to make invisible exceptions impossible.
Concretely: build a lightweight exception protocol into your contribution guidelines. Any deviation from a system token or component API gets a comment with three fields — what it deviates from, why, and who approved it. No approval required for shipping; approval required for the comment to be considered complete. This shifts the governance burden from gatekeeping to auditing. You can run a quarterly pass on tagged exceptions and decide which ones reveal a gap in the system worth closing.
The design systems that stay healthy at scale aren't the ones with the strictest rules. They're the ones where rule-breaking is visible. Sanctioned chaos is just called iteration. It's the unsanctioned kind that compounds into the 47-button-variant problem.
If you're not sure which kind you have: search your codebase for hardcoded color values. The number you find is a reasonable proxy for how much unsanctioned drift has already happened.
