Skip to content
Back to Design Hub

Design Debt Management

Tracking and paying down the gap between the design system and what shipped.

Visual DesignIntermediate

Why

Every ship-under-deadline decision creates debt: a one-off color, a hardcoded spacing, a component that should have been in the system. Untracked, it compounds until the UI is inconsistent and the system is irrelevant.

Google's research shows users form a first impression in 50ms, and 75% of judgments about website credibility are based on visual aesthetics. Consistent spacing scales (8px grid) reduce cognitive load measurably.

When

Continuously. Log debt as it's created, schedule a pay-down sprint each quarter, and track the debt burndown like a tech-debt burndown.

How

1. Log it — when you ship a one-off, add a ticket: "Replace #FF0000 in PromoBanner with --color-promo" tagged design-debt 2. Categorize — token debt (wrong color/spacing), component debt (should be in the system), pattern debt (inconsistent UX) 3. Prioritize — user-facing inconsistency (two button styles) > invisible debt (refactor) > nice-to-have 4. Pay-down sprint — dedicate 10–20% of each quarter to design debt; don't let it grow unbounded 5. Lint — stylelint bans raw colors/spacing; new debt can't ship without an explicit override 6. Audit — run the audit quarterly (visual regression + token usage report); surface the top 10 drifts 7. Sunset — when a component is replaced, track its usage; remove only when usage hits 0

Example

// design-debt log — a markdown file or Linear project tagged "design-debt" /* - [ ] token: replace #FF0000 in PromoBanner with --color-promo-500 (added 2026-01-15, #PR-1234) - [ ] component: extract PromoBanner into the system (3 one-off instances) - [ ] pattern: unify toast positioning — 3 components use top-right, 2 use bottom-center - [ ] spacing: replace 17px gap in UserCard with --space-4 (16px) */ // stylelint — prevent new token debt "declaration-property-value-allowed-list": { "color": ["/var\\(--color-/"], "gap": ["/var\\(--space-/"], } // Quarterly audit script — find raw values that should be tokens const rawColors = await grep(/#[0-9a-f]{6}/i, "src/**/*.{tsx,css}"); const rawSpacing = await grep(/\b\d+px/g, "src/**/*.{tsx,css}"); // except 1px borders console.log(`${rawColors.length} raw colors, ${rawSpacing.length} raw spacings — design debt`);

Common Problems

  • ⚠Debt not logged — one-off ships, no ticket, forgotten until a designer notices the drift months later
  • ⚠No pay-down time — debt grows every sprint, never a scheduled window to fix it
  • ⚠No lint prevention — new raw colors/spacing ship freely, debt compounds even while paying down

Best Practices

  • ✓Log debt when it's created — a ticket at PR time, not 'we'll fix it later' (you won't)
  • ✓Schedule a pay-down sprint each quarter — 10–20% of capacity, treat it like tech debt
  • ✓Add stylelint bans for raw colors/spacing — prevent new debt; overrides need an explicit reason

FAQ