Most token systems fail the same way. The file exists, it is well named, it is even generated from the design tool. And then a marketing page ships with a hex code typed straight into a stylesheet, because it was faster, and nobody notices for five months.
What makes a token authoritative rather than advisory?#
One property: it is impossible to render the surface without reading the token file. Not discouraged, not code-reviewed against — impossible. Every other definition of "source of truth" degrades into a naming convention that holds for as long as the team is small enough to remember it.
Three layers, in this order#
- Primitive — the raw value. orange-500 is #FD8800 and means nothing else.
- Semantic — the intent. action-primary points at orange-500 today.
- Component — the binding. button-bg-primary points at action-primary.
Components never reference primitives. That single rule is what makes a rebrand a one-line change instead of a quarter of work, because the semantic layer absorbs the change and nothing below it has to move.
/* primitive → semantic → component */
:root{
--orange-500:#FD8800; /* primitive: a value */
--action-primary:var(--orange-500);/* semantic: a meaning */
}
.btn-primary{
background:var(--action-primary); /* component: a binding */
}Where do token systems actually drift?#
Not in the product UI, which is usually well policed. Drift starts in three predictable places: marketing pages built under deadline, email templates that cannot use CSS variables, and anything a third-party embed styles for you.
| Surface | Typical drift | Fix |
|---|---|---|
| Marketing pages | Hardcoded hex under deadline | CI lint on raw colour values |
| Transactional email | No CSS var support | Build-time inline from the same JSON |
| Third-party embeds | Vendor stylesheet wins | Wrap in a scoped token bridge |
| Docs site | Separate theme file | Consume the published token package |
Lint the thing you care about#
A regex that fails the build on a raw hex outside the primitive file takes an afternoon to write and removes an entire category of drift permanently. It will annoy people in week one and be invisible by week four.
Publishing is the part people skip#
Tokens that live in a repo one team can push to are a shared file, not a package. Version them, changelog them, and let consumers upgrade deliberately. A token change that silently repaints a downstream product is worse than no token system, because it teaches everyone downstream to pin and stop upgrading.

