Most “token” projects start with a bulk export.
Hundreds of color styles leave the design file. Someone renames them in a JSON blob. CSS variables appear. Three months later marketing invents #4B41E1 inline, mobile uses a different spacing scale, and dark mode is a fork nobody merges.
Tokens are not a file format stunt. They are a contract for how visual decisions move from design intent into shipping code — with owners, layers, and a ban list.
The Design Tokens Community Group (a W3C Community Group) publishes a format so design tools and code generators can exchange those decisions without proprietary lock-in. That interoperability is useful. It does not replace product discipline about what is allowed to exist.

Shared primitives. Controlled ink. Not freehand on every surface.
Why dumps fail
A dump answers “what colors exist in the file?” A contract answers:
- Which values may components use?
- Who can add a new one?
- How do light and dark map?
- What breaks when we rename?
- How does CI reject freestyle hex?
Without those answers, tokens become a second junk drawer — only with better JSON formatting.
Three layers that stay honest
1. Primitive
Raw ramps: color.indigo.600, space.4, font.size.300. They document the material. UI code should rarely import them directly. Primitives change when the brand palette changes — rarely, on purpose.
2. Semantic
Role-based: color.text.muted, color.action.primary, color.surface.raised, space.section.y. Components and pages consume semantics. Themes and modes remap semantics to primitives.
3. Component (optional, sparse)
Only when semantics are not enough: button.padding.x. Every component token is a future regret if overused. Prefer extending semantics first.
When every button hardcodes a primitive, you have a palette dump, not a system.
Naming is product language
Bad names encode tools and accidents: Blue/500-copy-2, Gray 3 (final), spacing-from-figma-8.
Good names encode role and state:
color.border.strongcolor.text.inversecolor.feedback.dangerspace.section.yfont.display.weight
Alias across modes (light/dark, high-contrast) at the semantic layer. Do not duplicate entire component trees for each theme.
Ownership and change control
| Decision | Owner | Gate |
|---|---|---|
| Add a primitive ramp | Design systems lead | Brand review |
| Add a semantic token | Design + eng | PR + docs |
| One-off hex in a feature | — | Rejected unless dated exception |
| Breaking rename | Systems lead | Migration note + version bump |
| Deprecate token | Systems lead | Find usages; remove after soak |
If anyone can invent a token in a feature PR without review, the set becomes archaeology in six months.
Codegen is the bridge, not the product
Pipelines (Style Dictionary and similar) should emit platform outputs from one source: CSS variables, iOS/Android, documentation tables. The source of truth is the token set plus its human docs — not whichever tool last exported.
Track in CI where you can:
- Diff of semantic tokens on every PR
- Unused token detection for dead weight
- Contrast checks on text/surface pairs before merge
Dark mode and multi-brand
Map modes by reassigning semantics — for example color.text.primary points at different primitives in light vs dark. Multi-brand programs need a clear rule: shared primitives with brand semantic packs, or fully separate sets. “One file with everything” usually means nobody knows what ships where.
What tokens will not fix
- Broken information architecture
- Components with no keyboard model
- Performance debt from forty third parties
- Designers and engineers who never share a review channel
Tokens reduce accidental variance. They do not create taste, research, or process.
A practical adoption sequence
- Inventory colors, spacing, and type already in production (not only Figma).
- Define semantic roles for text, surface, border, action, and feedback.
- Map primitives; kill near-duplicates.
- Wire codegen to CSS variables used by the real component library.
- Ban free hex in lint for application UI paths.
- Document how to request a new token.
Closing
Adopt a standard exchange format when it helps your toolchain. Write the contract first: layers, names, owners, and “no free hex.” Then exports stop being archaeology and start being releases.
Building or cleaning a design system? Start a project inquiry with your current token file and three components that always drift. That is enough for a contract workshop.