TRANSMISSION 001

Design Systems at Scale

Token architecture, component APIs, and the versioning strategies that keep a design system alive past its first year.

11.08.2025·4 MIN READ·Systems × Design × DX

Every company builds a design system. Almost none of them survive. The average lifespan of a design system before it's "replaced" or "v2'd" is about 18 months. Not because the original system was bad — because it wasn't designed to evolve.

This is a systems architecture problem, not a design problem.

#Why Design Systems Die

Design systems don't die from lack of adoption. They die from success. When enough teams depend on them, every change becomes a coordination problem. When coordination becomes expensive, teams fork. When teams fork, the system fragments. When the system fragments, someone proposes a rewrite.

Design systems don't die from neglect. They die from success without infrastructure to sustain it.

The death cycle:

  1. Small team builds system for their needs
  2. Other teams adopt it
  3. Those teams need features the original team didn't anticipate
  4. Requests pile up, velocity drops
  5. Teams start building their own components "just this once"
  6. Two years later, there are three "design systems"

#Token Architecture

The foundation of a survivable design system is the token layer. Not "CSS variables" — a structured, semantic token architecture that separates decisions from options.

// Options — the raw values that exist
const options = {
  blue: {
    50: '#EFF6FF',
    500: '#3B82F6',
    900: '#1E3A5A',
  },
  spacing: {
    4: '4px',
    8: '8px',
    16: '16px',
    24: '24px',
  },
};

// Decisions — what the options mean
const tokens = {
  color: {
    signal: options.blue[500],
    surface: {
      primary: '#0A0A0F',
      elevated: '#12121A',
    },
    ink: {
      primary: '#EDEDED',
      secondary: 'rgba(237, 237, 237, 0.5)',
    },
  },
  space: {
    component: {
      gap: options.spacing[8],
      padding: options.spacing[16],
    },
    layout: {
      gutter: options.spacing[24],
      section: options.spacing[24],
    },
  },
};
KEY INSIGHT

The token layer is a mapping from intent to value. When you change the value, the intent stays stable. When you add a new intent, the values are already available. This is what makes the system evolvable.

#Component API Design

The component layer is where most design systems over-invest in flexibility and under-invest in constraints.

WARNING

A component with 15 props is not flexible — it's fragile. Every prop is a commitment. Every combination is a test case. Every edge case is a support ticket.

The principle I follow: fewer props, stronger opinions.

A Button component doesn't need size, variant, color, borderRadius, shadow, hoverColor, activeColor, and disabledColor as separate props. It needs:

interface ButtonProps {
  variant: 'primary' | 'secondary' | 'ghost';
  size: 'sm' | 'md' | 'lg';
  children: React.ReactNode;
}

Three variants. Three sizes. Nine combinations. All testable. All documented. All consistent.

#Versioning Strategy

This is where most design systems have no plan. The versioning question is: how do you ship breaking changes without breaking consumers?

Three strategies, one clear winner:

#Strategy 1: Semantic Versioning (SemVer)

The obvious choice. Major for breaking, minor for features, patch for fixes. Problem: a "major" version of a design system means every consuming app needs a coordinated migration. In a company with 30 apps, that's a project, not a version bump.

#Strategy 2: Subpath Versioning

// Old import
import { Button } from '@company/ds/v1';

// New import
import { Button } from '@company/ds/v2';

// Both work simultaneously

This lets consumers migrate incrementally. A single app can use v1 buttons on one page and v2 on another. Migration becomes a page-by-page effort, not a big-bang project.

#Strategy 3: Feature Flags in Components

The worst option. Don't do this. You'll end up with components that have both the old and new behavior, switched by a prop. The complexity compounds until nobody understands the component anymore.

KEY INSIGHT

Subpath versioning is the winner. It's more work upfront to set up the build system, but it eliminates the coordination cost of migrations — which is the actual thing that kills design systems.

#What Survived

The design system I maintained served 12 product teams for three years without a rewrite. Not because it was perfect — because the architecture made evolution cheap:

  • Token changes propagated automatically
  • Component APIs were constrained enough to prevent misuse
  • Subpath versioning let teams migrate at their own pace
  • A contributions model let teams add components without forking

The system is still running. That's the whole point.