Patterns: Multi-Brand Architecture
Multi-Brand Architecture
This pattern specifies a multi-brand architecture that keeps one semantic name set across brands.
Failure if ignored: brand values leak across outputs or require a mapped layer to resolve.
Architecture overview
Structure
tokens/
base/ # Shared base variables
color.json
spacing.json
typography.json
brand-a/ # Brand A specific
color.json
typography.json
brand-b/ # Brand B specific
color.json
typography.json
File structure is the API
Semantic names are the API. Consumers request color.surface.brand. The build selects the brand folder that defines that name.
This replaces a mapped collection with file selection.
JSON files are the contract input. The folder path is the selector. The semantic names stay the same across brands.
Rules:
- The semantic name set MUST match across brand folders.
- Build config MUST select exactly one brand folder at a time.
- Mapped variables MUST NOT exist in the contract graph.
File selection rule
File selection rule is shorthand for this model.
- The files are the contract input.
- The folder path and file name are the selector.
- The build or import list is the switch.
JSON-as-API: the file set is the interface and the selector.
This keeps brand choice out of a mapped layer and out of tool panels.
This is a file selection rule. It is not a hosted service.
Example selector:
tokens/brand-a/color.json
tokens/brand-b/color.json
Pick one folder. The semantic names stay the same. The values change.
If you can select files, you can switch brands. No map required.
Example build selection:
{
"source": ["tokens/base/**/*.json", "tokens/brand-a/**/*.json"]
}
Example CSS selection:
@layer base, brand;
@import "variables-base.css" layer(base);
@import "variables-brand-a.css" layer(brand);
Decision surface
Decisions live in files and build inputs, not in a mapped collection.
- Choose the brand by the source list or by CSS imports.
- Use alias modes in tools for preview. Do not store brand logic in a variables panel.
- Use one decision point. Do not add a second map.
Example preview:
Alias collection
Mode: brand-a
color.surface.brand -> {color.brand.primary}
Mode: brand-b
color.surface.brand -> {color.brand.primary}
Governance note
- The file list is the only switch.
- Changes to brand folders follow the contract review gate.
Shared base
All brands share base scales:
// tokens/base/color.json
{
"color": {
"gray": {
"0": { "$type": "color", "$value": "#ffffff" },
"100": { "$type": "color", "$value": "#f5f5f5" },
"200": { "$type": "color", "$value": "#e0e0e0" },
"900": { "$type": "color", "$value": "#1a1a1a" },
"1000": { "$type": "color", "$value": "#000000" }
}
}
}
Brand-specific
Each brand has specific variables:
// tokens/brand-a/color.json
{
"color": {
"brand": {
"primary": { "$type": "color", "$value": "#0066cc" },
"secondary": { "$type": "color", "$value": "#666666" }
},
"text": {
"primary": { "$type": "color", "$value": "{color.gray.1000}" },
"secondary": { "$type": "color", "$value": "{color.gray.900}" }
},
"surface": {
"default": { "$type": "color", "$value": "{color.gray.0}" },
"brand": { "$type": "color", "$value": "{color.brand.primary}" }
}
}
}
// tokens/brand-b/color.json
{
"color": {
"brand": {
"primary": { "$type": "color", "$value": "#ff0066" },
"secondary": { "$type": "color", "$value": "#00ff66" }
},
"text": {
"primary": { "$type": "color", "$value": "{color.gray.1000}" },
"secondary": { "$type": "color", "$value": "{color.gray.900}" }
},
"surface": {
"default": { "$type": "color", "$value": "{color.gray.0}" },
"brand": { "$type": "color", "$value": "{color.brand.primary}" }
}
}
}
Build configuration
Brand A build
{
"source": ["tokens/base/**/*.json", "tokens/brand-a/**/*.json"],
"platforms": {
"css": {
"transformGroup": "css",
"buildPath": "dist/brand-a/",
"files": [
{
"destination": "variables.css",
"format": "css/variables"
}
]
}
}
}
Brand B build
{
"source": ["tokens/base/**/*.json", "tokens/brand-b/**/*.json"],
"platforms": {
"css": {
"transformGroup": "css",
"buildPath": "dist/brand-b/",
"files": [
{
"destination": "variables.css",
"format": "css/variables"
}
]
}
}
}
Implementation guide
Step 1: Create base variables
Create shared base variables:
- Create
tokens/base/directory - Create base variable files
- Define shared scales (color, spacing, typography)
Step 2: Create brand-specific variables
Create brand-specific variables:
- Create
tokens/brand-a/andtokens/brand-b/directories - Create brand-specific variable files
- Reference base variables where possible
Step 3: Configure builds
Configure brand-specific builds:
- Create build configs for each brand
- Include base + brand-specific sources
- Generate brand-specific outputs
Step 4: Consume brand variables
Consume brand-specific variables:
- Import brand-specific CSS
- Use brand-specific variables in components
- Test brand-specific styling
Implementation rules
- Share base scales across brands
- Keep brand-specific variables minimal
- Reference base variables in brand variables
- Use the same semantic name set across brand folders
- Document brand differences
Failure modes
If multi-brand architecture is wrong:
- Duplication of shared variables
- Brand A values appear in Brand B output
- Maintenance burden
- Build complexity
- Mapped variables appear as a shadow layer
- Brand selection leaks into token names
- All brands end up in one output bundle
Out of scope
- Brand management tools (use existing tools)
- Brand switching at runtime (handle in consumption layer)
- Brand-specific design decisions (focus on structure)