Why I Prefer Design Tokens Over Hardcoded CSS Variables
CSS custom properties are powerful, but they're a delivery mechanism, not a system. Design tokens give you a source of truth that generates CSS, JS, and TypeScript from a single spec-compliant file.

A common pattern in modern front-end codebases: a variables.css file that starts clean and grows into something no one fully understands.
This works. But it has a ceiling. The values live in CSS, which means any consumer that isn't CSS — JavaScript, TypeScript, native mobile, email templates — either has to duplicate the values or find another way to read them. There's also no schema, no type safety, no way to enforce the naming convention, and no way to know if a token is actually used anywhere.
Design tokens address all of this.
What a design token actually is
A design token is a name-value pair stored in a format-agnostic source file. The W3C Design Token Community Group has been working to standardize that format, and Style Dictionary v4 adopted it.
That single JSON file is the source of truth. Style Dictionary reads it and generates whatever outputs you configure.
What the pipeline produces
For the Design Token Pipeline project, I configured three outputs from one token source.
CSS custom properties — for use in stylesheets.
JavaScript ESM exports — for use in component libraries or anywhere JS runs.
TypeScript exports — same as JS, but with type declarations for autocomplete.
One change to the source token propagates to all three. No manual sync. No drift.
The argument for CSS variables alone
CSS custom properties have genuine advantages that design tokens don't replicate at build time. CSS variables are runtime. You can change them with JavaScript, scope them to a component, override them in a media query, or swap a whole theme by toggling a class on <html>.
The answer isn't to choose one over the other — it's to use design tokens as the source that generates CSS variables. Your token file holds the canonical values; your CSS variables expose them at runtime.
Where the token approach earns its complexity
The overhead of a token pipeline isn't free. You're adding a build step, a configuration file, and a new mental model. That cost is worth it when:
- Multiple platforms consume the same tokens. If web, iOS, Android, and email all need the same brand colors, a shared token source is the only maintainable approach.
- The design tool is Figma with Tokens Studio. Tokens Studio can sync directly to a DTCG-format token file. Design changes in Figma propagate to code through a PR — no manual transcription, no drift.
- The team is large enough that enforcement matters. A naming convention in a comment is a suggestion. A naming convention enforced by a schema and a linter is a constraint.
Where it's probably overkill
A personal project with one developer, one platform, and a color palette that fits on one screen doesn't need a token pipeline. CSS variables and discipline are fine. The pipeline earns its complexity at scale — not before.
That's the honest version. The tooling exists to solve real problems. Use it when you have those problems.
:root {
--color-primary: #1a6cf6;
--color-primary-hover: #1558cc;
--color-primary-active: #1044a8;
--color-primary-disabled: #a8c3fb;
/* 200 more lines... */
}{
"color": {
"brand": {
"primary": {
"$value": "#1a6cf6",
"$type": "color",
"$description": "Primary brand color. Used for CTAs, links, and active states."
}
}
}
}:root {
--color-brand-primary: #1a6cf6;
}export const colorBrandPrimary = "#1a6cf6";export const colorBrandPrimary: string = "#1a6cf6";/* This is genuinely powerful and can't be replicated by build-time tokens */
[data-theme="dark"] {
--color-brand-primary: #6ea8fe;
}