The question I get asked most in interviews about design systems is where the source of truth lives — Figma or code.
My answer: the code. The canvas is a synced view of it. But that answer is cheap — everyone says it and most teams don’t behave like it. The version that costs something is the follow-up: how long can the two disagree before someone ships the difference?
That gap is the drift window, and almost nobody measures it.
A design system doesn’t fail when Figma and code disagree. It fails when nobody finds out for six weeks.
- Role: Design Engineer
- Client: Thought Industries
- Timeline: stood up and running August 2024; the move off Figma began around mid-2025
- What shipped: Figma Connect, published and live in Dev Mode
- Scope: buttons, badges, panels, a couple of inputs
- Skills spotlighted: design-to-code tooling, token architecture, knowing when to stop
What we actually built
Figma Connect binds a Figma component to the real coded component — the actual import path, props, and variant values. In Dev Mode the panel shows the true snippet rather than Figma’s auto-generated guess at CSS. I was an early adopter, and this shipped: designers saw real snippets, bound to real components, when work passed to development.
Two decisions made it work:
One component, one home — the canvas built like the code. The Figma library housed each component in exactly one place, the way a codebase does. Not a page of loose variants a designer duplicates and drifts. One source, composed everywhere else.
The states were mapped, not approximated. The connected Figma button matched the coded component’s actual states, and we deliberately mapped the naming in Figma onto the naming in code. That vocabulary work is the part people skip, and it’s the part that decides whether the binding survives contact with a real sprint. If a designer says “secondary” and the enum says outline, you haven’t removed the translation step — you’ve hidden it.
It ran on manual figma connect publish. Worth being precise about that, because it bounds the claim: the drift window was one publish, and a publish is a thing a human remembers to do. Not CI. Not automatic.
And it stayed alive the same way for about ten months — I kept handing in specs and checking the bindings held. That’s the honest shape of the maintenance: not a pipeline, a person. Which matters for what happened next.
Why it didn’t take off
It didn’t fail on the mechanism. It failed on what surrounded it.
The shipped product was an old Ember stack carrying a lot of technical debt. Connect binds the canvas to the components in the repo — but the UI actually rendering in front of customers wasn’t built from those components. So the binding was true and narrow: correct about the system, quiet about most of the product. We wired four component families. Every screen was made of more than that.
Then, around mid-2025, leadership changed. The new direction was to build from scratch — move to shadcn, iterate fast on new concepts, and stop investing in the old surface.
And underneath both: the organization was scaling down at the same moment AI tooling was ramping up. Maintaining a Figma mirror of a design system is a recurring salary cost. When headcount tightens and a coding agent can generate on-system UI from a typed contract, that mirror stops looking like infrastructure and starts looking like an expense with a name on it.
Nobody killed Figma Connect because it was bad. It stopped being worth what it cost.
What Connect can’t catch
Naming the hole matters more than the pitch, so:
- It only covers what you wire. Four component families were bound. Nothing tells you about the hundreds of screens assembled from everything else, and the binding’s confidence doesn’t scale down gracefully — a partially connected library reads as more trustworthy than it is.
- It says nothing about the product you actually ship. If the live UI is legacy code that doesn’t import the system, Connect is describing a parallel universe. Correctly.
- It doesn’t reduce the cost of the canvas. Connect makes the mirror accurate. It doesn’t make the mirror cheap. Someone still maintains every component in Figma, forever, and Connect adds a second artifact to keep current on top of that.
- Manual publish is a human step. One forgotten
publishand the window is open again, silently. There’s no failing build to tell you.
The first and third are the ones I’d raise on day one of a new engagement now.
Where it went instead
The end of this story is the beginning of another one. At Thought Industries the system moved to shadcn, the contract moved into a typed registry agents read before generating, and I maintained it in Pencil rather than Figma — cutting the cost of an agentic design system by taking the expensive canvas out of the loop. That’s written up in full here, including the parallel package I killed to get there.
I’ll be straight about the limit of my own claim: I left before that system really took off. We were working on improving generation accuracy with Claude Code while I maintained the system in Pencil. I built the foundation and set the direction. I didn’t get to see the curve.
The position this left me with
Figma Connect is good technology and I’d use it again — on a codebase whose shipped UI actually imports the design system, with publish wired into CI rather than into someone’s memory.
But it changed what I think the question is. “Where does the source of truth live” invites a tooling answer. The better question is what you’re willing to stop maintaining in order for the answer to be true.
Code is the source of truth. The canvas is a synced view. And the cheapest way to shrink a drift window turns out not to be a faster sync — it’s having fewer things that can drift.
