One Source of Truth: The Token Workflow
Design tokens give a product a single source of truth when one canonical tokens file is where every design decision lives, and every consumer — stylesheets, utility theme, design-tool variables — is generated from it. Keeping that true is a five-step loop: decide in the design tool, export the canonical file plus its consumer formats, commit it so the pull request is the review gate, consume the generated formats in code and design files, and route every later change back through step one.
The phrase single source of truth comes from information-systems design: store every fact exactly once and derive every other appearance of it, so agreement between copies is maintained by structure rather than by diligence. This article maps that principle onto the day-to-day token workflow — the loop, the failure each step prevents, who owns what, and one change traced end to end. It is the workflow chapter of our design tokens guide.
What are the five steps of the token workflow?
- Decide — in the design tool. Scale parameters, color seeds, semantic roles: Scale Composer is the surface where those choices are made and their consequences are visible — a seed change re-derives the ramps and the roles for both themes while you watch.
- Export — the canonical DTCG file plus the consumer formats
generated from it: CSS custom properties, a Tailwind v4
@themeblock, Figma Variables with hex alongside. One decision set, several renderings. - Commit — the tokens file lands in the repository, and the pull request becomes design review: history, rationale in commit messages, revertability.
- Consume — code references the custom properties or the theme; designers bind the Figma variables. Nobody on either side types a raw value.
- Change — the next edit starts back at step one: the tool re-imports its own file, the adjustment is made against the current truth, and the loop repeats. Round-trip preservation makes this safe — sections the tool doesn’t generate survive the re-import untouched, a tested property rather than a hope.
Drawn on a whiteboard, the workflow is a circle, not a pipeline — and the circle is the point. A pipeline ends, and whatever it ends at starts accumulating hand edits.
What failure does each step prevent?
Skip a step and a specific, predictable failure appears in its place:
- Skip export and hand-copy instead. Values retyped into CSS or Figma are second sources from the moment they land. Drift — the design file and the build disagreeing about values that are supposed to be identical — is the disease tokens exist to cure, and hand-copying reintroduces it at the first deadline.
- Skip commit. The file lives in tool state or on one laptop: no review, no history, no revert, and “which version is real?” returns as a question with several answers.
- Skip the change loop. Edits happen downstream instead — someone patches the generated CSS directly. Now the canonical file is fiction: the next honest export silently overwrites the patch, so people stop exporting, and the source of truth becomes write-only, then abandoned. The re-import discipline is what keeps the loop closed — because the tool reads its own file back, going through it is never slower than going around it.
Consuming has a quieter failure of its own — referencing exported values by copying them rather than by name — but that is binding discipline at the call site, not a broken loop.
The intuitive summary: a single source of truth is not something a team sets up once — it is a property that has to survive every change made afterwards, and each failure above is the same event, a second source sprouting where a step was skipped. The loop is designed so that at every step the cheapest action is also the correct one: regenerating beats retyping, committing beats emailing a file, re-importing beats re-deciding. Workflows persist when the lazy path and the right path are the same path.
See one source feeding every consumer in Scale Composer — the canonical file’s sections on one side, and the same names rendered as CSS, Tailwind and Figma exports beside them.

Who owns which step?
The loop distributes cleanly across roles. The designer owns decide — the judgment calls live there. Export and commit are the handshake where a private decision becomes shared, reviewable property. Engineers own consume in code; designers own it in the design file. Change belongs to whoever’s need triggered it — routed through the same gate as everyone else’s.
A useful frame — and it is a frame, not a technical fact: the tokens file
is the API between design and engineering, and it repays the same
disciplines an API gets. Versioned, through commits. Reviewed, through pull
requests. Documented, through $description fields that travel with the
tokens. Deprecated with a grace period instead of broken overnight. The
frame also predicts the sociology: disagreements about a value stop being
design-versus-engineering turf wars (“the file says 22, the build says
20”) and become a change proposal against one artifact both sides read.
On a two-person team — or a one-person one — the loop is the same with fewer handoffs. What the steps buy there is not coordination but memory: the commit history is the design log.
How do you retire a token without breaking consumers?
With a transition, exactly as an API would. Renaming or removing a token is
a breaking change for every consumer of the old name, so the old name
aliases the new one for a release — "accent-strong": { "$value": "{semantic.accent}" } keeps stale references resolving while the change is
announced — and removal happens after consumers have migrated, verified by
searching for the old name rather than by hoping. Deleting outright means
the break is discovered at the next build if you are lucky, and in shipped
visuals if you are not.
What does one change look like through the loop?
Trace a real one: the brand re-seeds its accent from blue — #2563eb,
which is oklch(0.546 0.215 262.9) — to a deeper indigo.
- Decide. The designer loads the project’s
design-tokens.jsoninto Scale Composer — the committed file, not a stale copy — and replaces the brand seed. The ramp re-derives around the new hue; the semantic roles keep pointing at the same steps; light and dark both re-derive from the one decision. - Export. The canonical file plus the CSS, Tailwind and Figma formats. Changed: ramp values and role resolutions. Unchanged: names, type, spacing — everything the change didn’t touch comes through the round-trip intact.
- Commit. The PR reads “re-seed accent to indigo — Q4 brand refresh”. The reviewer sees a values-only diff, confirms the on-accent pairings still clear their contrast floors, asks the blast-radius question, and approves. The commit message is the design log entry.
- Consume. On merge,
--accentresolves to the new value everywhere it is referenced — no component code changes. The design file updates its variables from the new export, and bound screens re-resolve without redesign. - Change. Two weeks later the hover step needs a nudge. The edit starts by loading the same file — which still matches what shipped, because nothing bypassed the loop.
What each role saw: the designer made one edit, the reviewer read one readable diff, the engineer shipped zero code changes, and the product shifted in one coordinated move. Decision-sized work for a decision-sized change — that is what the loop is for.
Run the loop once yourself
The loop is most persuasive at step five, when the tool hands you back your own decisions intact. Change one seed and watch it propagate — every export re-renders from the same source, and the sections your change didn’t touch come back exactly as they went in.