Design Systems Are Living Code, Not Screenshots
When the source of truth for a design system lives in a design tool, it drifts. When it lives in the codebase, it compounds. This is a quiet but consequential shift.
A design system is the accumulated set of decisions a team has made about how their product should look and behave. Colors, type, spacing, components, the rules that govern how they combine. In theory, it is a single, authoritative source that the whole team builds against. In practice, it is usually two sources that disagree with each other — the version in the design tool and the version in the codebase — and the team spends ongoing effort pretending they are the same thing.
The more interesting question, once you admit the two-source problem, is which of the two should be considered primary. For years the answer was "the design tool." For reasons that are now obvious in retrospect, that answer is shifting.
Why design files were the default source
Early in the web, the design tool was the detailed source and the code was the compromised implementation. You drew the button in Photoshop with a specific drop shadow, and then a developer approximated it in CSS. The browser couldn't fully render what the design tool could, so the design file was the "truth" and the code was the "best effort."
That gap closed a long time ago. The browser now renders anything a modern design tool can express. CSS custom properties and color spaces like OKLCH give the browser more expressive power than most design tools have caught up with. Modern web output is no longer a compromise — it is, in many ways, the more capable medium.
The design tool remained the source-of-truth by momentum rather than by capability. It's still where visual decisions are first made; it's still where the canonical palette "lives." But the product people use is the code, not the design file, and when they diverge, the code wins by default because the code is what ships.
What a living system looks like
The shift is: put the primary source in the codebase, and treat the design tool as a visualization of it.
This means several things in practice.
Design tokens in code. The palette, spacing scale, type scale, radius scale, motion durations — all expressed as design tokens in a format the code can consume directly. CSS custom properties, or a tokens.json, or a Tailwind config, or the equivalent in your stack. The tokens are the system. Everything references them. Nothing hard-codes their values.
Components in code. The authoritative Button is the <Button /> in the codebase, with its actual accessible label, focus state, disabled state, and loading state. Not the Button in Figma. The Figma Button is, at best, a faithful preview of the coded one.
Documentation alongside code. The reason to use a specific component, its accessibility properties, its constraints — all written next to the component, not in a separate wiki that drifts within days of being written.
Versioning like code. The system gets versioned, changes get reviewed, deprecations get communicated. Not because "everything should be code" as an ideology, but because versioned systems stop drifting, and design systems drift faster than almost anything else in a product.
The token story
Design tokens are the smallest unit of this new model, and they are what makes everything else possible.
A token is a named value. color.background.primary instead of #0b0d0e. space.4 instead of 16px. radius.lg instead of 12px. Named values are not a new idea — designers have been using them in design tools for years, as color styles and text styles. What's new is that the same tokens now live in code as the authoritative definition.
Tools like Tailwind CSS v4, with CSS-first config, have been pushing in this direction for a while. Color spaces like OKLCH mean the values themselves are now more expressive — you can adjust lightness on a color and get a perceptually-uniform result, rather than a result that looks slightly off in a way you can't explain. Design tokens in OKLCH, with generated shade scales and documented contrast ratios, are a considerably more powerful primitive than the hex-based palettes that preceded them.
The token story also solves the handoff problem by eliminating it. If the designer and the developer are both looking at a token called color.text.muted, they can argue about whether its value is right, but they can't argue about which muted they mean. The token is the name for the decision, and the decision has one home.
What changes when the system lives in code
Several things, some of them counterintuitive.
The design tool becomes a sketchbook, not a library. You use Figma to explore, to propose, to visualize. You don't use it to define. The definition lives in the repo. This is actually freeing — the design tool gets to be the playful medium it should have been all along, unburdened by the obligation to be the authoritative source.
Updates propagate automatically. Change a token value in code, and every component that references it updates. No manual sweep of every Figma file. No "forgot to update the light mode variant." The dependency graph is executable.
Testing becomes possible. You can write tests against your design system the same way you write tests against any other code. Contrast-ratio tests. Accessibility tests. Component visual regression. The system becomes verifiable in a way that a Figma library cannot be.
Designers work closer to the repo. Not necessarily committing code — but opening the repo, reading the token file, understanding what's there. The best designers I know already do this. The shift I'm describing just formalizes what the best practice already looks like.
The Figma library becomes a mirror. You generate Figma styles from the tokens, not the other way around. When the tokens change, a script regenerates the Figma library. The library is always in sync because it is downstream of the source.
Why teams resist
The obvious question: if this is clearly the better model, why isn't every team doing it?
A few reasons. The tooling has only recently become good enough. Tailwind v4, OKLCH, CSS custom properties with fallbacks, design tokens tooling — most of it settled into mature form in the last year or two. Before that, token-first workflows required heroic effort to maintain.
More subtly, it requires a shift in who holds the system. Traditional design ops teams own the Figma library. Code-first systems are more naturally owned by engineering or by a design engineering function. That ownership shift is political, and politics slows adoption even when the technical case is clear.
There's also a fear, among designers, that "the system lives in code" means "designers lose control." In practice, it often means the opposite. When the system is a Figma library no developer reads, designers have the illusion of control but not the reality. When the system is code that every developer uses, designers who contribute to that code have direct, enforced influence on the shipped product.
Practical steps
If you're trying to move a design system toward this model, the sequence that tends to work:
- Establish tokens in code. Whatever format fits your stack. Make them the one place visual values are defined.
- Migrate the palette first. It's the most referenced, most visible, and most commonly broken by drift. Getting the palette to one source is an outsized win.
- Then typography. Font families, sizes, weights, line heights.
- Then components. Pick the most-used component (usually Button or Input), make the code version the authoritative one, and delete the Figma version or mark it explicitly as a visualization.
- Generate the Figma library from code. Automatically, on a schedule or on merge. This is the step that closes the loop.
Most teams can do the first two in a week. The later steps take longer, but the value starts compounding as soon as the first tokens are in place.
The larger shift
This is part of a pattern. The center of gravity of product work is moving into the codebase. Design systems, visual decisions, token libraries, component documentation — the things that used to live in a separate design tool are moving into the repo because the repo is where the product actually lives.
None of this kills design tools. It reorients them. The design tool becomes the place you think in, and the code becomes the place you ship from. The system — the set of decisions that hold a product together — belongs to the shipped artifact. Anything else is a sketch of the system, and sketches don't compound.