concept tokens sounded like a silver bullet. You'd define colors, spacing, and type scales once, then reuse them everywhere. No more hunting for hex values. No more inconsistent shadows. But then it happened: your staff started treating tokens like config files, and every sprint brought new revisions. Someone wanted a 'primary-50' that didn't exist. Another designer needed a token for a one-off border radius. Before long, your token set had 400 entries, and developers were asking which ones were actually in use.
So where did it go off? And more importantly, what do you fix primary? This article walks through the most usual failure modes — naming confusion, over-engineering, creep — and gives you a concrete sequence of operations to salvage your token stack before it becomes another legacy headache.
The Real-World Failure repeat
According to internal training notes, beginners fail when they optimize for shortcuts before they fix the baseline.
How tokens become tech debt—quietly
I watched a mid-sized item crew roll out block tokens with genuine excitement. Six weeks later, they were drowning. Every button, every card, every input site carried a token reference. The concept setup crew had mapped every visual property to a variable. Sounds correct, proper? flawed. The catch is that tokens don't lower complexity by default—they shift it. What used to be a lone hard-coded color value turned into a chain: color-background-primary → color-neutral-100 → #f5f5f5. One hover state adjustment meant tracing three layers. That's not abstraction. That's indirection. And indirection, when over-applied, becomes your new tech debt.
The revision loop that kills velocity
A developer needs to adjust the error state on a form input. She opens the Figma file. The concept token says color-feedback-error-light. She checks the codebase—same token. But the component manager wants a softer red. Now what? Changing the token value breaks every other error state across the app. Creating a new token means updating the block stack spec, the component library, and eight screens that use variants. That's a four-hour ticket for a solo hex revision. swift reality check—designers in this loop stop trusting tokens. They hard-code the red. Then another dev hard-codes a slightly different red. Three sprints later, you have seventeen reds and zero confidence in the setup. The fixture that promised reusability now guarantees rework.
Most units skip the hard question: what exactly is this token abstracting? A color token that maps to a lone component state is just a named constant—fine, but not reusable. A token that maps to a semantic role (like 'danger' or 'success') across twenty components is powerful, but one off value pollutes everything. The trade-off is brutal: tight coupling reduces flexibility, loose coupling inflates the token count. Neither feels good when you're three weeks from a launch.
'We spent two sprints building the token stack. We've spent three sprints patching the blowback.'
— Lead engineer, after the sixth revision request on a primary button
The failure repeat isn't exotic. It's logical, repeatable, and almost invisible until the revision count doubles. concept tokens feel like a safety net—until you realize the net is woven from the same brittle threads you tried to substitute. The fix isn't more tokens. It's fewer, smarter ones. But that requires a naming convention that doesn't lie to you initial—which is exactly where we're headed next.
Semantic vs. Atomic: The Naming Trap
Why 'color-primary-500' Breaks Everything
Atomic tokens look innocent enough. color-primary-500, spacing-4, font-size-16. They describe the value, not the usage. That sounds fine until a designer renames the primary blue to color-accent-500 in Figma, while the codebase still expects color-primary-500. Now you have two names for the same blue, a six-hour search-and-substitute, and one very confused developer. The real trap is not the naming convention itself—it is the collision of two mental models. The concept stack staff thinks in atomic: 'This is blue, hex #2563eb, call it what it is.' The item crew thinks in semantic: 'This blue is used for primary buttons, call it color-button-primary-bg.' When both layers exist in the same token file, engineers open guessing which one to use. faulty sequence. They pick the atomic one because it is easier to find, then apply it to a context where it breaks—a hover state that needs a different opacity, a dark mode that maps to a different hue. Suddenly a solo token adjustment ripples across ten unintended components. I have seen units burn two sprints unpicking this exact knot.
'Atomic tokens are great for paint-by-numbers. Semantic tokens are great for intent. Mixing them without a clear boundary is how you paint yourself into a corner.'
— Lead designer, after reverting 47 pull requests
The fix is not to abolish one aesthetic. It is to admit that atomic naming only works inside a one-off, isolated domain—a monochrome icon set, a typographic growth with no semantic overload. The second you attach meaning (danger, success, disabled), the atomic label lies. color-red-500 is not red in dark mode—it is a washed-out maroon. That hurts. Semantic names absorb context; atomic names flatten it. Most units skip this gut check, rushing to generate tokens from a repeat file dump, and then wonder why revisions spike the primary window a theme switches.
When Atomic Works—And When It Bites
Atomic naming thrives in one place: a raw palette. Neutral grays, row primaries, opacities, fixed spacing units. No context, no baggage. Just raw values you never revision—or shift only once a year. The catch is that units rarely stop there. They let atomic tokens leak into component definitions. color-primary-500 becomes the background for every call-to-action button. Fine until an accessibility audit says the contrast is too low. Now you must adjustment the token value, and suddenly every component that used color-primary-500 anywhere shifts. The border on the card. The text of the secondary link. That decorative row in the header. One fix, four regressions. swift reality check—semantic tokens would have isolated the button background to color-bg-cta-primary, leaving the decorative line on a separate semantic leash. Atomic naming works when you promise never to use it outside the palette. The moment you treat it as a component-level token, you are building a house without shear walls. One strong wind and the whole frame torques. I have watched units revert to hard-coded hex values just to stop the cascading failure—something we will cover in chapter 4, but the root cause is always the same: the naming layer lied about what it controlled.
Three Patterns That Actually Reduce Revisions
According to published workflow guidance, skipping the calibration log is the pitfall that shows up on audit day.
Tiered token architecture
Most units flatten everything into one giant list. That's the primary mistake. A tiered setup splits tokens into three layers—global primitives, semantic aliases, and component-specific overrides. Global primitives hold your raw values: blue-500, spacing-8, font-xl. Semantic aliases map those to purpose: color-button-primary-bg points to blue-500. Component overrides handle edge cases like a disabled state or a dark-mode variant. I have seen units cut revision cycles by sixty percent just by enforcing this layer boundary. The catch? Engineers want to skip straight to the semantic alias and skip the primitive layer entirely. That shortcuts the whole stack—you end up with aliases hard-coded to hex values instead of primitives, and the next update breaks everything.
Alias maps for context
An alias map is a lone source of truth that connects a concept intention to one—and only one—primitive. Think of it as a bridge: color-surface maps to gray-50 on light mode, gray-900 on dark mode. No ambiguity. The snag surfaces when designers add variation—surface-primary, surface-secondary, surface-tertiary—all pointing to slightly different grays. Suddenly your three tokens become twelve, and half the staff can't remember which surface token goes on a card versus a modal. We fixed this by constraining alias maps to exactly one use per context. 'But what if the concept needs nuance?' Tune the primitive, not the alias. That rule alone stopped our rollback count from spiking every sprint.
'Every alias should answer one question: what is this for, not what does it look like.'
— Senior designer reviewing their initial token audit
Constraint-based token generation
Here's where most units bleed phase—unlimited token creation. Designers invent new tokens for every variant, every hover state, every random component mockup. Constraint-based generation forces you to derive tokens from a fixed set of parameters: capacity, weight, mode, and role. If a token doesn't fit those four dimensions, it doesn't get created. Period. swift reality check—when we capped our spacing tokens to a 4-point volume (4, 8, 12, 16, 24, 32, 48, 64) and forbade manual overrides, the block stack's revision rate dropped by half. The trade-off? Some pixel-perfect layouts break. But here's what I tell units: a broken layout with consistent constraints fixes faster than a perfect layout with thirty orphan tokens. You lose one day fixing the seam instead of two weeks auditing token bloat. That hurts less.
Why units Revert to Hard-Coded Values
The friction of over-engineering
Most units don't abandon tokens because tokens are a bad idea. They abandon them because the token setup they built feels like a bureaucratic slog for every solo pixel. I have watched otherwise patient engineers snap and type #1a2b3c directly into a component file after the fifth phase they had to open a token dictionary just to set a border-radius. That is not laziness — that is an efficiency gap. When a token lookup takes three clicks and a scroll, but hard-coding a value takes two keystrokes, the seam blows out. The anti-block here is what I call premature abstraction: you decide every shade, every spacing unit, every corner radius needs a named variable before you know which ones actually repeat. A 4px corner used in exactly one place does not require a token called --radius-card-corner-compact. That token adds zero reuse value and increases cognitive load for everyone downstream. The friction is invisible on a Figma board — it shows up in code reviews where a developer pushes back, or in sprint planning where a minor style shift spawns a six-item checklist.
'We spent two weeks naming tokens, then spent two more weeks explaining to the front-end crew why they couldn't just use the hex value.'
— UX engineer, fintech unit crew
When token lookups expense more than they save
The second reason units revert is over-granularity — splitting tokens into so many layers that the stack becomes its own rabbit hole. Sure, you can separate color-background-primary from color-background-primary-hover from color-background-primary-pressed from color-background-primary-disabled. But now any developer adjusting a button has to audit four tokens instead of one. The math flips: you saved a tiny bit of future flexibility but lost real-slot productivity today. I have seen concept systems where a one-off button component required eleven token references. Eleven. That is not reusability — that is a tax. The catch is that granularity feels virtuous in a repeat capture. It looks thorough. It impresses other token enthusiasts. But in daily use, it creates a constant context-switch penalty. Every window someone has to pause and think 'wait, do I use zone-inline or space-stack for this margin?', the stack has already lost. Hard-coding looks ugly, but it wins on speed. And speed, in a shipping group, often beats purity.
The typical failure block runs like this: a concept-ops lead builds a beautiful, layered token taxonomy, announces it with fanfare, and then watches adoption stall at 30%. The remaining 70% of the crew quietly hard-codes values because the official path requires too many decisions. That is not a training snag — that is a layout glitch. You built a setup optimized for theoretical correctness instead of daily ergonomics. The fix is ruthless subtraction: remove every token that does not save a future edit or enforce a meaningful constraint. If a token is only used once, kill it. If a token requires a lookup table to understand, rename it or remove it. The goal is not a complete stack — the goal is a stack people actually use. A subsystem of 40 tokens that everyone reaches for beats a library of 400 tokens that everyone ignores. Hard-coding returns when friction exceeds tolerance; lower the friction, and hard-coding becomes the slower path again. That is the only metric that matters.
Maintenance expenses Nobody Accounts For
A field lead says units that capture the failure mode before retesting cut repeat errors roughly in half.
Token wander and orphaned values
Six months in, you will find a $color-line-blue token that nobody touches anymore—yet it still lives in every component library, every Figma file, every CI check. I have watched units accumulate hundreds of these ghosts. The real expense isn't the storage; it's the cognitive tax. Every phase a designer or developer opens a palette, they must mentally verify: does anyone actually use this? Most skip the question, ship it anyway, and the seam blows out later. That is token slippage—values that technically exist but semantically died.
Orphaned values are worse. A group migrates from Material layout 2 to 3, deprecates $shadow-elevation-low, but forgets to delete it from six back-end repos. Three sprints later, a new hire applies the old token. The result? A button that floats six pixels too high. The bug ticket lands on a PM's desk, takes two hours to diagnose, and nobody bills that phase. rapid reality check—auditing these orphans once per quarter costs roughly one engineer-day per 200 tokens. Scale to 1,200 tokens, and you lose a week. That is not theoretical; that is what maintenance debt looks like when you never track which values are actually consumed.
The fix is brutal but effective: delete everything unused once per quarter. Set a cron job that flags tokens with zero references in your concept stack's compiled output. If a token survives two consecutive purges without a lone consumer, kill it. No mercy. The alternative is a repository that feels like a hoarder's attic—and nobody wants to work in that attic.
'We saved three hours of button tweaks and lost forty hours of alignment meetings.'
— layout-ops lead, after a token migration that touched eight repos
Governance overhead across units
Most units skip this: coordination debt. When template tokens span three offering squads, a solo rename triggers a cascade. The web group updates $spacing-md from 16px to 20px. That seems fine until the mobile group, using the same token for a different component, sees their cards overflow. Now you orders a cross-group sync, a migration plan, and a rollback strategy—all for what was supposed to be a one-line change. That hurts.
The catch is that governance scales non-linearly. Two units? You call a shared Slack channel. Five units? You volume a weekly token council. Ten units? You demand a dedicated designer whose sole job is telling people which tokens to deprecate. I have seen that role created, funded for six months, then abandoned because the overhead killed the framework's flexibility. The trade-off here is sharp: tighter governance reduces wander but increases friction for fast-moving squads. Looser governance speeds up shipping but guarantees a rat's nest of conflicting values within two quarters.
One practical block: instead of enforcing one global token set, allow per-crew overlays with strict expiration dates. A group can introduce $spacing-card-inner-their-feature-v2—but the token auto-deletes after ninety days unless promoted to the shared library. This keeps experimentation cheap while preventing orphaned values from fossilizing. The trick is automation, not meetings. Set a bot that pings the group lead two weeks before expiry: 'Renew or remove.' Most will remove. That is the outcome you want.
What usually breaks opening is the social contract: someone on the platform team decides that $color-error must be hex #D32F2F, but a piece designer on a different floor has been using $color-error as #C62828 for six months. The fix? A one-off source of truth? Yes. But also a willingness to say: 'Your token is faulty. Fix it in your branch, not in the shared layer.' Hard conversations pay maintenance dividends. Soft ones produce a token stack that nobody trusts—and that is when crews revert to hard-coded values. The next section picks up that exact breaking point.
A mentor explained however confident beginners feel, the pitfall is skipping the failure rehearsal; says the quiet part out loud — most rework traces back to one undocumented assumption that looked obvious on day one.
When Not to Use block Tokens at All
Small crews with high churn
A three-person startup with a rotating front-end stack should not touch concept tokens. I have seen this template kill more momentum than bad spacing. When your offering roadmap changes weekly — and your layout framework has no dedicated owner — tokens become frozen abstractions. You define a color palette, then swap the line two sprints later. That semantic token you named --color-primary? Now it maps to a value that clashes with the new identity. The revision spend eats the slot you hoped to save. Worse, no one remembers why --spacing-md equals 12 pixels instead of 16. The original designer left. The new hire shrugs and inlines a hard-coded 14px. That is token bloat without maintenance capacity.
Prototyping before framework stabilization
Prototypes live to be thrown away. block tokens are built to survive. Those two goals fight each other. If you are still discovering your visual language — still toggling between border-radius 4px versus 6px every review cycle — introducing a token layer adds friction, not discipline. You end up aliasing temporary values, then forgetting to clean them. Six months later, the codebase holds a graveyard: --radius-experimental-a, --spacing-temp-3, --color-trial-purple. That is not reusability. That is technical debt wearing a framework name tag.
— A biomedical equipment technician, clinical engineering
The catch: this advice feels backward. Every conference talk says begin tokens early. But early-stage products call speed and plasticity, not abstraction layers that lock decisions before they are mature. Choose velocity over stack purity. You can always tokenize later — what you cannot undo is a six-month investment in a naming convention that never matched your real product. That hurts.
Open Questions and FAQ
A shop-floor trainer explained that the pitfall is treating symptoms while the root cause stays in the checklist.
Can you automate token cleanup?
Yes—but only after you name things right. I have seen groups import a Figma plugin that scans for orphan tokens (values defined but never used in any component). That catches maybe 40% of the mess. The deeper rot is tokens that are referenced but mapped to the off alias—say a 'neutral-100' surface that actually renders as a hover state nobody intended. No automated linter catches semantic drift. Fix that by writing a simple CI script that compares token output across every platform (web, iOS, Android) each phase you push to your token repository. If the RGB values diverge, the build fails. That solo guardrail cut revision rework by half on a project I consulted for last quarter.
How do you handle platform-specific tokens?
Duplicate them. Yes, duplication feels faulty in a concept framework—engineers hate repeating themselves. But the alternative is worse: a lone 'shadow-elevation-2' token that tries to serve both CSS box-shadow and iOS .layer.shadowOffset simultaneously. The physics don't match. What usually breaks primary is the blur radius—Android's rendering pipeline interprets it differently, so your 'soft card' looks smudged on a Pixel. The fix is brutal but stable: append a platform suffix (--web, --ios, --android) on any token where rendering behavior diverges. That way you keep a shared semantic layer (--surface-elevated) while the platform-specific variant absorbs the math. Quick reality check—this means three token files instead of one. Maintenance cost goes up, but revision count drops. Choose your pain.
'We tried one-size-fits-all tokens for six months. The iOS lead was manually overriding 20% of them by week three.'
— pattern engineer, B2B SaaS platform (mid-migration)
That quote reveals the real trade-off: platform-specific tokens look like governance failure but are actually honesty. The crews that succeed log exactly where divergence is allowed and who signs off on a new platform variant. Not a committee—a one-off named owner per platform. Without that, you get four engineers each adding their own 'correct' shadow token and calling it alignment.
One more question that stumps most crews: 'Who deletes tokens?' Most orgs have no sunset policy. The token file grows like digital plaque—hundreds of values nobody references, but nobody dares remove. Automate a weekly report listing tokens with zero usage across all platforms. Send it to the same platform owner. If no one objects in two sprints, delete them. That hurts the primary time. After that, units stop hoarding.
Your next move is not a bigger aid. It is a lone rule: every token must prove its existence across two platforms within one month of creation or it gets flagged. Enforce that, and the revision spiral loosens.
Summary: Your Next Four Steps
Audit primary, then prune
Stop. Before you rename a one-off token or push another commit, run a full inventory. I have seen groups with 1,200 tokens — and only 47 actually used in production. The rest were ghosts: deprecated values, half-built semantic layers, or naming experiments nobody cleaned up. Export your token set to a flat list. Cross-reference it against your actual component library. Every unused token is a future argument waiting to happen. Kill them. The catch is — pruning feels wasteful. It's not. A lean set of 80 tokens beats a bloated catalog of 400 that nobody trusts. Wrong order causes the whole stack to rot.
'We had 600 tokens. After the audit, we kept 73. The first review cycle after that dropped by 60%.'
— Lead designer, fintech platform, after a three-week cleanup sprint
Set a naming convention and enforce it
Naming is where most crews bleed revisions. You pick color-primary for the button background. Then a developer uses color-accent for the same value because it looked more 'brand-like.' Now you have two tokens pointing at the same hex — and two designers changing one but not the other. Fix this by picking one axis: either semantic (what it does) or atomic (what it is). Never both in the same setup. The pitfall? units pick semantic for the UI and then add atomic tokens for exceptions. That hybrid is the trap. Constrain yourself: one pattern, one source of truth. Enforce it with automated linting or a Figma plugin that flags rogue values before they reach code. You will still get pushback — but fewer emergency meetings.
Most units skip one step: they record the convention but never test it against a real use case. Try renaming ten tokens with your chosen scheme. If the logic bends after three, your stack is fragile. open over. I have watched projects waste a month on naming debates that could have been settled in two hours with a solo working example. That hurts.
Constrain before you expand
Limit the number of tokens any component can reference. Hard rule: no more than three token layers per element — base, state, and one override. More than that and you are building a debugging labyrinth. The editorial move here is brutal: if a component needs five tokens, it is either poorly designed or your token system is too granular. Shrink the component or flatten the tokens. Do not do both. A concrete anecdote: a dashboard app I worked on had a card component referencing seven tokens. Every sprint, someone changed one token and broke the visual hierarchy across three views. We cut it to three tokens. Revisions dropped by half. The trade-off was less visual nuance. That was fine — nuance was causing chaos.
Govern with a lightweight process
No committee meetings. No sign-off gates with five stakeholders. Governance here means one person owns the token set, one tool tracks changes, and one rule governs additions: every new token must replace or merge into an existing one — no net growth without a deprecation. That sounds simple. It is not — because teams instinctively add rather than substitute. The rhetorical question you need to ask: 'If I add this token, which one dies?' If the answer is none, reject it. Document why in a public log. I have used this rule across three design systems and it is the single highest-leverage action (yes, I said it — but it actually works) for stopping revision creep. Your next step: schedule a 90-minute audit this week, not next sprint. Start with the buttons. They always lie.
Comments (0)
Please sign in to post a comment.
Don't have an account? Create one
No comments yet. Be the first to comment!