HomeJournalThis post

DTCG Design Tokens Without Vendor Lock-In

A graph-first DTCG migration preserves aliases and composite tokens, validates the stable format, generates CSS, and diffs semantic output before cutover.

JP
JP Casabianca
UI/UX designer and full-stack engineer · Bogotá

DTCG design tokens provide a stable interchange format, but converting JSON keys is the easy part. A safe migration preserves value types, token aliases, semantic meaning, platform output, and the dependency graph that products already consume.

This tutorial migrates a realistic color, typography, spacing, shadow, and border set into the stable design token format. A dependency-free validator resolves references, detects cycles, and compares generated CSS before any vendor source is removed.

Inventory before writing DTCG design tokens

Start by freezing the current token source, generated artifacts, consuming packages, and screenshots or computed-style fixtures. Inventory primitive values, semantic names, component tokens, themes, modes, deprecated aliases, custom extensions, and vendor-only metadata. Record which fields influence output even if they are not tokens.

A proprietary design token format may encode type implicitly in a path or transform name; the stable DTCG shape makes types and values more explicit. Migration scope should include only tokens whose meaning is understood. Unknown values enter a quarantine list rather than being guessed into a standard type.

Runnable artifact: The validator transforms a small proprietary set, resolves an alias, checks a typed dimension, and rejects reference cycles. Its dtcg-token-migration.test.mjs receipt keeps the article's simplified boundary executable and reviewable.

Save the inspectable proof as dtcg-token-migration.test.mjs and run node dtcg-token-migration.test.mjs. Expected final line: PASS: DTCG aliases preserved.

import assert from "node:assert/strict";
const legacy={blue:"#3157ff",action:"{blue}",space:8};const dtcg={$type:"color",blue:{$value:"#3157ff"},action:{$value:"{blue}"},space:{$type:"dimension",$value:{value:8,unit:"px"}}};const resolve=(name,x,seen=new Set)=>{if(seen.has(name))throw Error("cycle");seen.add(name);const v=x[name].$value,m=typeof v==="string"&&v.match(/^\{(.+)\}$/);return m?resolve(m[1],x,seen):v};assert.equal(resolve("action",dtcg),legacy.blue);assert.deepEqual(dtcg.space.$value,{value:8,unit:"px"});console.log("PASS: DTCG aliases preserved");

Map value types without flattening semantics

Translate colors, dimensions, durations, numbers, fonts, shadows, strokes, gradients, and composite structures according to the stable format's definitions. Unit-bearing values should not become bare numbers; a font family should not be treated as an arbitrary string if its consumer expects a typed value. Groups can establish inherited type where appropriate, but local exceptions need explicit handling.

Preserve descriptions and deprecation notes in supported fields or named extensions. The point is interoperable meaning, not visually similar JSON. Build a table from each legacy type and transform to its destination representation plus validation rule.

  1. 1Inventory

    Freeze graph + outputs

  2. 2Transform

    Type + preserve aliases

  3. 3Diff

    Compare semantic output

  4. 4Cut over

    Move reversible cohorts

Figure 3: Authority moves only after semantic and rendered comparisons pass.

Treat token aliases as a dependency graph

Token aliases should remain references when they express design intent. A semantic action color pointing to a palette blue is different from copying the hex value, because future palette changes should travel through the relationship. Parse references into a directed graph, reject missing targets and cycles, and resolve a deterministic value for each output platform.

Review alias depth and cross-theme references rather than enforcing an arbitrary universal limit. When a legacy system uses transformed aliases, document whether the DTCG graph plus transformer extension can preserve that meaning or whether a deliberate token split is required.

Model typography, shadow, and border composites

Composite tokens reveal weak migrations because their subvalues combine distinct types. A typography token can include font family, weight, size, line height, and letter spacing; shadows can be arrays; borders combine color, width, and style. Create fixtures that exercise optional fields and platform mappings rather than test only colors and spacing.

If a consumer cannot accept the composite directly, transform it into named platform output while retaining one canonical token. Avoid creating several competing source representations merely to satisfy current build scripts. The design token migration should reduce ambiguity, not spread it across transforms.

Generate CSS through an explicit transform boundary

The canonical DTCG document is not itself a CSS variables file. A transformer resolves aliases, converts typed dimensions and colors, applies naming policy, and emits stable custom properties. Style Dictionary can participate in that pipeline, but its configuration and extensions remain versioned implementation code rather than hidden standard behavior.

Sort output deterministically and include a generated-file header with source and transformer versions. Keep platform naming separate from canonical token paths so a CSS naming change does not rewrite the source model or pretend to be a semantic design decision.

DTCG design tokens reference graph migrationImplicit proprietary JSON becomes a typed DTCG graph where a semantic action token references a palette token before deterministic platform output. legacy JSONimplicit typespalettespacingactionCSS + appsstable output
Figure 1: Portability lives in typed values and preserved reference meaning, not renamed JSON keys.

Diff semantic output before cutover

Compare resolved old and new values by consumer name, type, theme, and mode. Text diffs are useful but insufficient when ordering or formatting changes; normalize into a semantic table first. Then run computed-style fixtures and focused visual regression across representative components, including dark mode, density, high contrast, and deprecated aliases.

Classify every difference as expected migration, pre-existing inconsistency, transform defect, or blocked unknown. Zero diffs is not always the goal—some defects may be intentionally corrected—but every visible change needs an owner and release note.

Legacy familyDTCG typeKey checkOutput proof
ColorcolorColor space + channelsCSS value
SpacingdimensionValue + unitCustom property
ActionaliasTarget existsResolved color
TypographycompositeMember typesPlatform fixture
Figure 2: The migration matrix protects source semantics and platform output together.

Cut over consumers in reversible cohorts

Publish the DTCG source and generated artifacts under a versioned package, then move a small consumer cohort before the entire design system. Keep old and new generation paths in dual-run mode long enough to compare outputs, but prevent authors from editing both sources. The canonical-authority flag changes only after source and production consumers agree.

Provide codemods or alias shims for renamed variables, with removal dates. Monitor missing variables, fallback usage, bundle changes, visual diffs, and support reports. Rollback restores the generated artifact and consumer binding without throwing away the migrated canonical graph.

Govern portability after the migration

Vendor neutrality is maintained, not achieved once. Keep the canonical file valid against the named stable DTCG specification; place vendor metadata in documented extensions; test at least one independent parser or the dependency-free reference validator; and preserve output fixtures. Review proposals that add tool-specific fields for whether they encode source meaning or temporary build convenience.

Track unresolved extensions and alias depth. When the standard or tooling changes, run the semantic diff suite before adopting it. The durable outcome is a graph whose meaning remains inspectable even if the current design-token tool is replaced.

Keep the standard and the transformers separate

The stable DTCG format report is the migration authority, the community group's FAQ clarifies scope, and Style Dictionary token documentation describes one consumer rather than the canonical format. Use the site's design-system foundations, Figma variable naming, token starter explanation, and migration-under-pressure field note to negotiate naming, design-tool translation, and rollout without letting any single exporter become the source of truth.

Migrate one alias knot before the whole library

Select a small family containing a primitive color, a semantic alias, a component alias, a typed dimension, a deprecated name, and one vendor extension. Convert it to the stable format, resolve both old and new graphs, and compare platform outputs byte-for-byte where stability is promised and semantically where formatting may change. DTCG design tokens reduce lock-in only when the canonical graph can be validated without the former vendor tool and when consumers can switch independently behind an explicit compatibility window.

Archive the original token path, converted node, resolved value, emitted platform value, and any extension preserved outside the stable core. That DTCG design tokens crosswalk gives designers and engineers a shared place to review semantic drift, instead of accepting a successful JSON parse as proof that color spaces, dimensions, composites, and aliases survived.

Test the crosswalk with one consumer that does not use the migration transformer, even if it is only a small validation script. This independent DTCG design tokens reader demonstrates that the canonical graph is genuinely portable and that vendor-specific metadata can be ignored without destroying the standard value or its reference relationships.

DecisionEvidence retainedStop condition
Inventory before writing DTCG design tokenssource digest, token count by family, alias edges, output targets, consumers, extensions, unknown fields, and migration ownerunrecognized data is silently dropped because it does not fit the destination example
Map value types without flattening semanticslegacy type, destination $type, normalized $value, unit conversion, extension policy, and a representative round-trip fixturetwo tokens that render similarly lose distinctions required by another platform
Treat token aliases as a dependency graphreference source, target, path, resolved typed value, cycle and missing-target checks, and intentional flattening exceptionsthe migration replaces every alias with a literal and calls the output semantically equivalent
Model typography, shadow, and border compositescomposite schema, required and optional members, resolved subvalues, target transform, serialized output, and unsupported-case behaviora composite is stringified into opaque shorthand that downstream tools cannot inspect
Generate CSS through an explicit transform boundarycanonical source hash, transformer and configuration version, target platform, naming rule, emitted artifact hash, and warningstool-specific convenience fields become the only representation of token meaning
Diff semantic output before cutovernormalized old-new pair, semantic classification, affected consumers, visual fixture, approval, and rollback mappinga clean JSON diff substitutes for platform rendering and component evidence
Cut over consumers in reversible cohortscohort, package versions, authority flag, compatibility aliases, output comparison, rollback command, and shim retirement dateteams can edit old vendor JSON and new DTCG files concurrently
Govern portability after the migrationconformance version, extension registry, independent validation, output fixtures, unresolved portability risks, owner, and next reviewone vendor's successful import is treated as proof of ecosystem portability
DTCG design tokens decision ledger. The DTCG design tokens ledger exposes whether aliases, types, extensions, and outputs survived the authority transfer.

DTCG design tokens remain portable while types, aliases, extensions, and generated outputs stay inspectable. Revalidate the canonical graph before changing the standard version, transformer, or authority flag.