Skip to content
← ALL WRITING

2026-04-23 / 10 MIN READ

Design Tokens Built to Survive the Next Rebrand

How to design a DTC token layer that survives a rebrand with one value change instead of 40 renames, plus the semantic structure that makes it work.

Every rebrand I have ever been part of had the same crisis moment. The new color gets approved. The designer opens the token file to update it. And then they realize the token is named --brand-purple-500, the new color is pink, and there are 43 references to purple across the codebase. What should have been a one-value change becomes a two-week rename operation with a side of merge conflicts.

The fix is semantic naming, and it is unreasonably cheap to get right up front. This is the pattern I run on every DTC brand build and what the nine brands I have shipped have converged on.

Rebrand simulator
Brand-named (brittle)
  • --brand-purple-500#6a3bff
  • --brand-purple-hover#5a2bef
  • --brand-purple-tint#eee6ff
  • --btn-purple#6a3bff
  • --link-purple#6a3bff
Semantic (durable)
  • --signal#6a3bff
  • --signal-hoverderive(-8L)
  • --signal-tintderive(+60L)
  • --btn-primaryvar(--signal)
  • --link-primaryvar(--signal)
Brittle tokens require 5 renames on rebrand. Durable tokens require 1 value change.

The two kinds of tokens

Every design token is either literal (describes the value) or semantic (describes the role). A literal token is --blue-500 or --brand-purple. A semantic token is --signal, --danger, --surface, --ink.

Literal tokens read well in a style guide and translate directly from Figma color styles. Semantic tokens read as slightly weird on first glance (what is --signal?) but they abstract the brand decision away from every consumer of the token. That abstraction is the entire point.

When a rebrand lands, literal tokens have to be renamed everywhere they appear. Semantic tokens just get a new value. Every button, link, callout, and header that consumes --signal keeps working unchanged.

A two-layer token file

The pattern I use has two layers inside a single tokens file. The top layer is literal: the raw color values, type sizes, spacing values. The bottom layer is semantic and only references the top layer.

/* Literal layer: raw values, rarely consumed directly */
--pink-500: #fd109a;
--ink-900: #0a0a0a;
--paper-50: #fafafa;

/* Semantic layer: what the site actually uses */
--signal: var(--pink-500);
--ink: var(--ink-900);
--paper: var(--paper-50);
--btn-primary-bg: var(--signal);
--link-color: var(--signal);

Every component, every page, every stylesheet references the semantic layer. Never the literal one. That one rule is what makes the rebrand durable.

When the rebrand happens, I change --pink-500: #fd109a; to --teal-500: #00ccaa; and update the semantic pointer: --signal: var(--teal-500);. Twenty-second operation. Zero component files touched.

What semantic actually means

"Semantic" is a word that gets overused. I use it in the specific sense of describing the role a token plays in the system, not the appearance it has. --btn-primary-bg is semantic because the role (primary button background) is stable across rebrands. --purple-bg is not semantic because the role is encoded in the appearance; if the button turns pink, the token name lies.

Good semantic names I use across DTC builds: --signal (primary brand accent, one color), --ink (foreground text), --paper (background surface), --surface-elevated (raised cards, modals), --border-subtle, --success, --warn, --danger. Nothing named by appearance. Everything named by role.

Bad semantic names I see in other people's systems: --primary, --secondary, --tertiary. The problem is that "primary" is a relative ordering, not a role. When the brand shifts and the primary color becomes the secondary, every component has to be audited to see whether the semantics still hold. I have stopped using primary/secondary/tertiary entirely on the brand layer.

The exception: explicit brand accents

There is one case where I keep a literal-ish token: the brand color itself, because the surface needs a way to say "I am rendering the brand color right here, with full knowledge that the rebrand changes it." On this site, that token is --pink, and it exists alongside --signal. They currently hold the same value (#fd109a), but they mean different things.

--signal means "primary brand accent, whatever that is." --pink means "explicitly the pink color." An italic accent on the hero h1 uses --pink because the designer intent is "the specific color of Michael's current brand mark." A button uses --signal because the designer intent is "the current primary brand accent."

When the rebrand comes and the brand color shifts to teal, --signal becomes var(--teal-500) and buttons keep working. --pink gets renamed to --teal (because the semantic is now "the specific teal of the brand mark") and the five explicit accent callsites get updated. That is fewer than ten touches across a site.

The thing that always breaks: raw hex in components

The failure mode is a junior engineer (or a senior engineer in a hurry) who writes color: #6a3bff inline in a component instead of color: var(--signal). Every raw hex is a rebrand landmine.

Two ways to catch this. The first is a lint rule that flags raw hex in CSS and JSX. I use a custom Stylelint rule on larger codebases. The second is a quarterly grep: grep -r "#[0-9a-fA-F]\{6\}" src/. Anything that shows up that is not in the tokens file gets ticketed.

The related failure mode is Tailwind arbitrary values. bg-[#6a3bff] is a raw hex wearing a bow tie. Either ban them via a Tailwind config rule, or include them in the same quarterly grep. I have seen Tailwind arbitrary values slip through code review three times in the past year because reviewers scan for hex and miss the bracket syntax.

Why Figma-first teams struggle with this

Figma's color styles are literal by default. When you pick a color in Figma, it gives you a swatch with a hex value. If you name the style "Brand Purple," you are encoding the current appearance into the name. When the brand changes, Figma users have to rename every style.

The move I have every Figma-using team make: rename their color styles to semantic roles. The "Brand Purple 500" swatch becomes "Signal." The local color value does not change. What changes is what the swatch means. When the rebrand ships, the swatch value updates and every file that referenced "Signal" automatically renders the new color.

The same move applies to text styles. A style named "Body 16 / Regular" is literal. A style named "Body" is semantic. Font sizes can move between rebrands; the role does not.

Naming by role instead of appearance is the single cheapest structural investment a DTC brand can make before its first rebrand. It costs 20 minutes and saves 20 days.

Two traps

The first trap is over-abstraction: building a five-layer semantic hierarchy where --button-primary-bg references --button-primary-base-color references --interactive-color references --signal. I have seen systems like this on enterprise design system tools. They are unreadable to anyone who was not there when the hierarchy was built. Two layers is enough. The literal layer and the semantic layer. If you feel the pull toward three, ask what it buys you.

The second trap is inconsistent semantics: some tokens use role names and others use appearance names in the same system. Pick one convention and enforce it. Drift across convention is worse than consistent mediocrity. I inherited a design system once where half the color tokens were semantic and half were literal; the rebrand that followed took three weeks of tag-team renaming.

Running the rebrand

When the rebrand actually happens, the playbook is:

First, update the literal layer. One file, one PR. No component touches. Ship it to staging. Visually QA every page. Find the places where the semantic layer does not cover the new brand (usually the explicit brand-color callsites I described above).

Second, update the explicit callsites. Usually five to ten. Rename them if the new brand color wants a new semantic ("brand-pink" becomes "brand-teal") and update references.

Third, handle the edge cases. Usually one or two places where the brand color was doing double duty in a way that does not translate (an illustration with a gradient from the brand color to white, for instance). Fix these directly in the component.

Fourth, run the hex grep. Fix anything that leaked. Ship.

A durable token system gets a rebrand to production in about a day of work. A brittle system takes two to three weeks. The gap compounds every rebrand.

Frequently asked questions

What if I have more than one brand accent?

Name each accent semantically. A brand with a primary accent and a secondary accent can use --signal and --signal-alt or --signal and --accent. Avoid calling them primary and secondary if the relative ordering is likely to shift; use roles that describe how each is used (attention-grabbing, emphasis, etc).

Should I token every shade of a color or just the brand color?

Token the brand color and any shades you actually use. If you only use --signal and --signal-hover, those are the only two you need. Building a full 10-shade scale for a color you use in three places is the opposite of durable; it is overbuilt. Start small and add shades when a production file demands one.

Does this apply to typography tokens too?

Yes. Semantic type tokens are things like --heading-display, --body, --mono, --caption. Literal type tokens are things like --font-48, --font-serif-bold. The same two-layer pattern works: literal font sizes and families at the top, semantic type roles below. When you decide to change the display font, you update one value, not 20 references.

How do I convince the brand consultant to accept semantic names?

Two moves. First, frame it in the language of the rebrand: "this makes the next rebrand one day of work instead of two weeks." Consultants who have been through a rebrand understand immediately. Second, keep the Figma style library visually identical to what they built; only the names change. They can pick colors the same way they always did.

Is this pattern overkill for a brand that will never rebrand?

Every brand rebrands eventually. The ones that "never rebrand" tend to acquire or be acquired, which triggers a rebrand anyway. But the pattern has a second benefit even without a rebrand: semantic tokens make it easier to ship a dark mode, a holiday theme, or a landing-page variant, because you are changing one variable instead of auditing every surface.

Sources and specifics

  • Pattern derived from nine DTC brand builds across 2023-2026 and the token architecture running on this site.
  • Two-layer (literal then semantic) structure is the one I use now. Earlier projects used flat literal naming, which is the specific failure I am describing.
  • The "rebrand in a day" claim is from direct work; the "two to three weeks for brittle systems" claim is from three separate brand engagements where I inherited a literal-named token set and had to migrate before the rebrand could ship.
  • See also: the brand architecture hub, running two DTC brands off one token base, and color accessibility without beige.
  • Methodology is part of the Operator's Stack, the productized version of this brand-plus-code workflow.

// related

Let us talk

If something in here connected, feel free to reach out. No pitch deck, no intake form. Just a direct conversation.

>Get in touch