The Design Handoff Is the Contract. The Codebase Keeps Breaking It
The Figma file is the contract, and the codebase is the party that keeps renegotiating in private. Every team claims the design is the agreed-on specification, then ships whatever the component library already supports, whatever the backend will tolerate, and whatever the engineer remembers from the Slack thread two sprints ago. The result is a product that resembles the design the way a cover song resembles the original: close enough that nobody sues, far enough that nobody is proud.
That drift isn’t a tooling problem. It’s a disagreement about which artifact gets to be right when the two don’t match. The honest way to read a project is to hold the file and the repo side by side, section by section, and ask which one wins and why.
Two Sources of Truth, One Product
The design file wants to be the spec. It carries intent, hierarchy, states, the reason a button sits where it sits. The codebase wants to be the spec too, because it’s the thing users actually touch and the thing that compiles.
Both claims are reasonable. Both are also incomplete.
A good piece on this names the trap directly: calling any one artifact the single source of truth flattens a question that’s really about which decisions live where. Visual intent and interaction states belong in the file.
Data shape, error handling, and performance budgets belong in the repo. When teams pretend one artifact owns everything, the other one silently overrides it at implementation time, and nobody logs the override. Fixing that pattern is often why teams bring in an outside software development service to wire the plumbing. The problem is one of engineering infrastructure, not of designers trying harder.
When the File Should Win
The file wins whenever the question is “what did we agree this experience would feel like.” Spacing systems, type ramp, empty states, the hover that tells a user something is clickable, the sequence a form walks through on a failed submit. Somebody made these decisions deliberately and wrote them down in the one place deliberate design decisions get written down.
The handoff only holds up when the file is ready to be read as a contract. Figma’s own handoff guide is blunt about what that takes: annotations on anything non-obvious, consistent use of the design system, explicit status on which frames are ready, and context that explains intent, not appearance. A file without that scaffolding is a mood board, and engineers are right to override it.
When the Codebase Should Win
The codebase wins whenever reality intrudes. A design that assumes 40ms API responses loses to a service that returns in 900ms. A layout that assumes three tags per record loses the day a customer imports forty.
A modal that works beautifully at 1440px wide needs to survive a 320px phone held with one thumb. When engineers deviate on these points, they’re enforcing constraints the file didn’t price in, not being disrespectful.
There’s also an argument that goes further: that code is not the source of truth either, because the implementation keeps getting judged against something that came first. Call that the production experience, the brand, the user’s expectation. The point stands. The codebase is authoritative about what currently exists, which is a smaller claim than being authoritative about what’s correct.
Where the Two Should Share Custody
Some decisions have to live in both places or they don’t survive. The honest list is shorter than most teams admit:
- Design tokens. Color, type, spacing, radius, and motion values that are defined once and consumed by both the design tool and the build. If a hex code lives in a Figma style and also as a hard-coded string in three components, the two will diverge by the next sprint.
- Component contracts. The props a component accepts and the states it supports, agreed on by the designer who draws it and the engineer who builds it. A “Button” with seven variants in Figma and four in code is not a shared component.
- Content states. Loading, empty, error, and overflow. Files go silent here and codebases improvise, which is how the same empty-state message ends up written four different ways in one product.
- Accessibility rules. Contrast, focus order, hit targets, and semantics. Easy to specify in a file, easy to lose in a build, and nobody notices until an audit.
Shared custody only works if there’s a mechanism for it. That usually means token pipelines that read from one definition, a component library the designers actually design in, and a review step where a changed component triggers both a Figma update and a pull request.
Leave a Reply