Design tokens solve a real problem but introduce a different one. The first problem is that design values are scattered across stylesheets, component files, and a designer's memory. Tokens consolidate them into a single source of truth. The second problem is that a token system creates a build artifact that now has to stay in sync with two different environments: the design tool and the codebase. Keeping those synchronized is where most teams run into trouble, and the trouble is rarely where they expect it.
What a token pipeline actually looks like
A basic pipeline: a designer exports a Tokens Studio JSON file, a build script (usually Style Dictionary) transforms it into CSS custom properties, a CI step commits the output, and components reference the generated variables. Each point in that chain is a potential failure.
The simple version works without friction. You have 50 color and spacing tokens, one theme, and one output target. Style Dictionary runs in under a second, the output file is small, and everything stays in sync because one person owns both sides.
The version that breaks: 200 tokens, three themes, token aliases that reference other aliases, and two output targets. The transformation step now needs to resolve alias chains across theme contexts before producing output. Any token defined in one theme but missing from another creates a gap that shows up as a runtime CSS variable resolution failure, usually in a context you never test locally.
The alias chain problem
Three-tier token architecture is the recommended pattern: primitive tokens hold actual values (hex colors, rem numbers), semantic tokens alias primitives with meaning-bearing names, and component tokens alias semantics for specific components. The pattern works, but it starts to fail when alias chains grow longer than two levels.
Consider a chain: --button-bg aliases --interactive-primary, which aliases --color-brand-500, which aliases --palette-indigo-600. A runtime bug in one theme produces a missing value. Tracing the failure means walking four levels of indirection to find the point where the dark theme defines --palette-indigo-600 differently, and the semantic level didn't account for it.
The practical constraint we apply in DesignVerse's token processing is a two-level alias limit. When a token file has a chain longer than two aliases, the generation step resolves it and flags the over-indirection. The output is cleaner, and component code can reason about exactly two levels of abstraction when debugging.
Making primitive tokens private
One concrete fix for the alias discipline problem is keeping primitive tokens out of the production CSS output entirely. If --blue-600 is a primitive, it should never appear in a component's stylesheet. Style Dictionary supports a private: true flag on token groups, which suppresses them from the final output file. Only the semantic layer ships to production. Engineers cannot reference a primitive that does not appear in the generated file or IDE autocomplete.
This sounds obvious, but most teams skip it because the extra configuration feels like friction at setup time. Once you have debugged a global color change that only partially worked because 12 component files had direct primitive references, the configuration pays for itself.
Theme switching and the completeness problem
CSS custom property overrides on :root handle most theme-switching use cases, but they create a completeness requirement. Every token needs to be defined in every theme context. When a team adds tokens incrementally, it is easy to add a new token to the light theme and forget to add it to the dark theme override.
The symptom is subtle: the component renders correctly in light mode, falls back to an undefined value in dark mode, and produces a result that may or may not look visually wrong depending on what CSS does with an unresolved custom property. The bug is invisible in day-to-day development because most developers work in a single theme.
DesignVerse runs a completeness check at import time. For every token that appears in a component's generated output, we verify that a value is defined for all declared theme modes. Missing definitions are flagged before the generation step produces a file, not after a designer encounters the gap in a review.
Spacing tokens and the unit question
Spacing tokens are where units cause the most disagreement. Designers think in pixels. CSS best practice uses rem. Design tools typically export unit-less numbers. When Style Dictionary converts a spacing token, it needs to apply a unit transformation: a token value of 16 needs to become 1rem or 16px depending on project convention.
The correct answer for most web products is rem for layout spacing, because it respects user font-size preferences set in the browser. The practical answer is whatever the team decides before they have 80 components built. Changing the unit convention afterward requires touching every component that references any spacing token.
DesignVerse stores the unit transformation rule as a project setting so every generation run applies the same conversion consistently, regardless of who triggers the export.
When tokens are not the right abstraction
Tokens represent values, not relationships. A shadow that should become more pronounced on hover cannot be expressed as a single token. It needs either two tokens (default shadow and hover shadow) or a component-level style that handles the state transition. Teams that try to tokenize every design decision end up with a token file that is as complex as the component code it was meant to simplify.
The scope of a token system should be limited to values that are genuinely shared across contexts: colors, spacing, type sizes, border radii, and transitions. Component state behavior lives in component code, not in a token file. Trying to encode hover behavior or animation curves as tokens is technically possible but practically unmanageable at scale.
When a full three-tier hierarchy is overkill
There is a version of token architecture that is genuinely too complex for a small product team. If your product has one visual theme, no multi-platform targets, and a component library under 30 components, a full primitive-semantic-component three-tier system will cost more in maintenance than it saves in consistency. A flat semantic layer with sensible naming works fine.
The three-tier system pays off when you need to white-label the product, support multiple themes, or serve more than one platform from the same source. We are not saying the simpler approach is always right. We are saying the architecture should match the actual complexity of your product, not the theoretical complexity of design tokens as a pattern. Starting flat and adding tiers when the need is concrete is more honest than engineering for a multi-theme future that may never arrive.
Getting the pipeline to actually run reliably
The most underrated part of a token system is the build step. Style Dictionary needs to run on every token change, and the output needs to land in the right place for the consuming application. Teams that skip CI integration end up with token files that drift from production output. A designer changes a value in Tokens Studio, pushes the JSON, and nothing in the application updates because nobody ran the build.
The pattern that works is treating the token transformation exactly like a code build step: it runs on every PR that touches a token file, the output is committed or published to a package, and the consuming codebase references the published artifact. DesignVerse's API endpoint for CI integration handles this: post your token file to the endpoint, get component output back in the pipeline, without maintaining a local Style Dictionary config. Running tokens in production is an operational discipline, not just a design decision. The teams that get it right treat the token file as a contract between design and engineering, where both sides agree to what each name means before either side changes a value.