Token build-output drift is the gap between what your DTCG token files declare and what your build actually emits as CSS custom properties. This post defines six computable, static checks — path walks, two-build diffs, alias resolution — that close that gap, each with an explicit statement of what it can and cannot prove.
Why a source-to-output contract matters
The single most useful contract in a design-token pipeline is the mapping from source token path to emitted variable name. If you can state, for every leaf token in your DTCG files, exactly one CSS custom property that a Style Dictionary build must produce — and verify it mechanically — you have made drift computable instead of anecdotal. This matters now for a concrete reason: the ecosystem is mid-transition. DTCG 2025.10 is a Final Community Group Report dated 28 October 2025 and is considered stable, Style Dictionary has had first-class DTCG support since v4 but does not yet fully support 2025.10, and zeroheight’s tokens automation is moving to Style Dictionary v5 with a hard deadline on legacy export formats. The zeroheight transition can shift variable names and generated structure, and partial 2025.10 support is a gap that Rule 4 scopes. The checks below are vendor-neutral and need no browser. Rules 2 and 4 are static source checks; Rules 1 and 6 need one converted or built output; Rules 3 and 5 need two builds.
The computable rules
Each rule is stated as an invariant, a check you can implement with JSON parsing, path walking, or a two-build diff, and what the check cannot prove. A build that emits a file proves only that the build ran; the proof boundaries must stay separate, a principle articulated well by Identity Forge.
Rule 1: Every leaf with $type and $value emits exactly one variable
Invariant. For every leaf token in the source DTCG JSON — an object with $value and no nested token objects — the configured build emits exactly one CSS custom property, for every leaf its filters let through. Composite tokens (typography, shadow, border) and $root tokens need a project-defined expected-name set instead, because one leaf can emit several properties.
Check. Parse each .tokens.json file, walk the object tree, and classify every node as a leaf or a group. For each leaf, resolve its effective $type (its own, inherited from the nearest parent group, or taken from its alias target) and confirm that one resolves. Then parse the emitted CSS and count occurrences of each custom property. Build the map path → variable name and assert a one-to-one map between filtered leaves and emitted properties: no filtered leaf without a variable, no variable without a leaf.
Why the $type check is strict. The DTCG format spec lets a token get its type directly, by inheritance from a parent group, or from an alias target. If none of those yields a type, the types technical report says tools must treat the token as invalid and must not infer a type from its value. So an unresolvable type is invalid input, and the check should fail before the build, not after.
Cannot prove. That the emitted value is semantically correct (e.g., that a color renders as intended), or that the variable is actually consumed anywhere in your CSS.
Rule 2: Aliases resolve to leaves only
Invariant. Every curly-brace alias reference ({a.b.c}) resolves to a leaf token, never to a group or a sub-property of a token.
Check. During the same path walk, collect all string $values matching the alias syntax, resolve each against the token tree, and assert the target is a leaf. Style Dictionary v5 enforces this direction: the v5 migration guide says references only work when they point to a design token, and its examples label a reference to a token group ({foo}) and a reference to a sub-property ({foo.nested.attributes}) as “not allowed”.
Cannot prove. That the resolved value is type-compatible with the referencing token (JSON Schema cannot follow token references, and cannot properly validate $value content when $type is inherited, per the DTCG JSON Schema project).
Rule 3: Rebuild identity across two runs
Invariant. Running the same build twice on unchanged input produces byte-identical output. Name generation must be a pure function of the source path.
Check. Build once, snapshot the output directory (hash the files), build again, and assert the hashes match. This is the cheapest drift detector you can own: any nondeterminism — timestamp injection, iteration-order-dependent naming, environment-dependent transforms — shows up immediately.
Cannot prove. That the naming function is stable across versions. Determinism within a version says nothing about whether a Style Dictionary or zeroheight upgrade changes the function. Cross-version stability is Rule 5’s territory: a two-build diff across a version bump.
Rule 4: Dimension and duration units conform to DTCG 2025.10
Invariant. Every dimension token’s $value is an object {value, unit} with unit px or rem; every duration token’s $value has unit ms or s.
Check. Static validation over the parsed JSON: filter leaves by $type, assert the shape and unit membership. This is a pure data check, no build needed.
Stability caveat. These unit constraints come from the DTCG 2025.10 format module, a Final Community Group Report dated 28 October 2025, stated as stable. Treat the unit sets as stable grounds for a check. Note, however, that Style Dictionary’s DTCG page is explicit that 2025.10 “does not have full support yet” and that support is work-in-progress in v5 — so do not assume the build layer handles every 2025.10 feature. This rule checks your source conformance; it does not certify your build’s conformance.
Cannot prove. That the emitted CSS unit matches the source unit after any transform step — especially if Tokens Studio transforms are in the chain (see the FAQ).
Rule 5: A version bump produces an empty diff, or an explicitly listed one
Invariant. Upgrading Style Dictionary (or a zeroheight-driven regeneration) changes build output only in ways you have reviewed and accepted.
Check. Before the bump: build, snapshot. After the bump: build, snapshot, diff. The diff must be empty, or every changed file must appear on an explicit allowlist with a human-approved reason. This is the two-build diff that turns “migration surprises” into a reviewable artifact.
Why this rule matters now. zeroheight’s migration guidance notes that while the file format stays the same, “variable names and generated structure can shift in places,” and that a small number of tokens that used mode inheritance or alias chains “may resolve slightly differently under v5.” Their recommended practice — run the new export side-by-side with the old one and diff — is exactly Rule 5. zeroheight’s platform outputs are generated by Style Dictionary v5, its legacy formats are no longer offered for new outputs, and support for previous export formats ends at the beginning of November 2026. The vendor advises diffing before a production switch, so teams on that path should run this check before cutting over.
Cannot prove. That the approved diff is complete. A text diff shows changed names and values, but not whether var() references resolve to the same values (the alias-chain case zeroheight warns about). Pair it with a resolved-value comparison if your risk profile demands it.
Rule 6 (optional): Legacy conversion is not type-refactoring
Invariant. Converting legacy token files to DTCG must not silently change token types.
Check. Before/after diff of $type values across the conversion. Style Dictionary’s legacy-to-DTCG converter moves $type from shared groups onto individual tokens but does not refactor common types — for example, it does not convert size to dimension. Rule 4 only inspects leaves already typed dimension or duration, so it will not catch a size token. Catch that with a named type check against the spec’s type list. The separate convertToDTCG utility can instead condense types onto groups, depending on its applyTypesToGroup option, so treat any $type placement change as a diff item.
Cannot prove. That a type is correct for your design intent — only that conversion did not change it behind your back.
Rules at a glance
| Rule | How checked | What it proves | What it cannot prove |
|---|---|---|---|
| 1. Leaf → one variable | JSON parse + path walk + CSS parse, bijection assertion | Complete, unambiguous source→output mapping | Value semantics; the variable is consumed |
| 2. Aliases resolve to leaves | Alias resolution during path walk | No group/sub-property references (v5 requirement) | Type compatibility of resolved values |
| 3. Rebuild identity | Two builds, output hash equality | Byte-identical output within a version | Stability of naming across versions |
| 4. Unit conformance | Static shape/unit validation per $type |
Source conforms to DTCG 2025.10 units | Build-layer 2025.10 support |
| 5. Bump diff empty or listed | Two-build diff against an allowlist | Version bumps produce no unreviewed changes | Semantic completeness of the approved diff |
| 6. Conversion ≠ refactor (optional) | $type diff across conversion |
No silent type changes | Design-intent correctness of types |
Toolchain facts that shape these checks
Style Dictionary v5 requires Node.js 22.0.0 or later and is described as a drop-in upgrade for most users — but the source’s “majority of users” is doing work in that sentence, which is precisely why Rule 5 exists rather than trust. If your tokens come from Tokens Studio, they must pass through @tokens-studio/sd-transforms before Style Dictionary sees them, adding a transform layer where values can change before the build — so snapshot after the full chain, not after Style Dictionary alone. And remember the schema limitation: the DTCG JSON Schema can validate token files structurally, but JSON Schema cannot follow token references or properly validate $value content under inherited $type, so schema validation complements but never replaces Rules 1–3. Pipelines that put a validation gate between design export and CSS emission, as described in this automated Figma-to-CSS sync write-up, are structurally the right shape; these rules are what belongs inside that gate. For a plain-language orientation, zeroheight’s DTCG explainer is a reasonable primer, though it calls the spec “still technically in draft”, which conflicts with the 2025.10 final-report status. Use the spec itself as the authority.
FAQ
Do these checks require Style Dictionary specifically? No. Rules 1–4 operate on DTCG JSON and emitted CSS and work with any builder. Rule 5 works with any tool whose output you can snapshot. The Style Dictionary-specific facts here (leaf-only references, Node 22+, the v3 converter’s behavior) matter because so many pipelines — including zeroheight’s — are built on it.
Can JSON Schema replace these rules?
No. It validates structure but cannot follow {alias} references or properly validate $value under inherited $type. Use it as a fast pre-filter; Rule 2 does the reference-level work.
We use Tokens Studio. Where do we snapshot?
After the full chain: Tokens Studio → @tokens-studio/sd-transforms → Style Dictionary → CSS. Snapping only after Style Dictionary would miss changes introduced by the transforms.
What exactly changes at zeroheight in November 2026? Support for previous (legacy) export formats ends at the beginning of November 2026, and legacy formats can no longer be selected for new outputs. New platform outputs are generated by Style Dictionary v5, and variable names and generated structure can shift in places — run the side-by-side diff of Rule 5 before your legacy format disappears.
Does Style Dictionary fully support DTCG 2025.10? No. It has had first-class DTCG support since v4, but the 2025.10 spec “does not have full support yet,” with work in progress in v5. Rule 4 checks your source files against the stable spec; it does not certify your build’s coverage of the spec.
The Bottom Line
Verdict: adopt Rules 1, 3, and 5 immediately; add 2 and 4 as static validators; treat 6 as a one-time migration gate. The core deliverable is a machine-checkable map from every DTCG source token path to exactly one emitted CSS custom property, plus a two-build diff policy that makes every Style Dictionary or zeroheight version bump an explicit, reviewed event instead of a silent rename. Rules 2 and 4 are static source checks; Rules 1 and 6 need one converted or built output; Rules 3 and 5 need two local builds. All are vendor-neutral, cheap to implement, and honest about their limits: they prove structure and determinism, not design intent or downstream consumption.
How This Guide Was Built
This review is based on official documentation — the DTCG 2025.10 format module and types technical report, Style Dictionary’s DTCG and v5 migration pages, zeroheight’s tokens-automation migration guide, Tokens Studio’s Style Dictionary docs, and the DTCG JSON Schema repository — plus a curated dossier of secondary sources. No tool was run hands-on for this post; no builds were executed, no diffs were produced, and no screenshots exist. Every sourced factual claim links to its source; the rest is guidance.
