Variable Design Standard
Open specification for design variable governance. Defines JSON structure, naming rules, validation, and versioning on DTCG 2025.10 format. Three layers. No mapped collections.
Govern variables across brands
After building Aurora at GM across 4 brands, I wanted a governance layer on an existing format that could handle multiple brands without adding complexity. The JSON file set is the API surface: file paths and variable names form the contract, and a rename is a breaking change.
Naming, handoff, and layer proliferation
Teams use different terms: design tokens, style properties, variables, constants. The terminology split is a symptom of a deeper problem: there is no standard for how design variables should be governed across tools and teams. This creates:
Naming confusion: Designers call them one thing, developers another. Handoff breaks because vocabulary is split.
No governance: Variables change without rules. Breaking changes ship to production without notice.
Tool lock-in: Figma Variables, Tokens Studio, and code-based systems use incompatible formats and reference syntax.
Handoff breaks: Design and code don't align. No way to track which variable version is deployed.
No validation: Invalid variables pass review and cause build failures downstream.
Layer proliferation: Teams add mapped collections between base and semantic layers to solve brand switching. Each extra layer means extra reference hops, extra naming decisions, and extra surfaces to audit. Variables should be easy to reason about, without requiring a specialist to untangle.
In this case study
Treat variable names as an API
Variable Design Standard (VDS) is a governance layer on the DTCG 2025.10 format. It defines naming rules, validation requirements, versioning strategy, and adapter patterns for handoff as teams and products grow. It uses three layers and selects files for each brand, without extra reference hops.
VDS defines three layers only. Base, Alias, Component. Implementations must not add a fourth layer between Alias and Base:
Base variables: Raw scales and palettes. The only place literal values live.
color.gray.900,space.4Alias variables: Semantic intent. Reference base variables.
color.text.primary→{color.gray.900}Component variables: Scoped control when needed.
component.button.color.background→{color.surface.brand}
Tool adapters
Tool exports are inputs, not the contract. Adapters normalize Figma, Tokens Studio, and other formats into VDS:
Governance checks
Variable names are treated like an API. Changes are reviewed before merge:
- Naming rules validated in CI (dot-separated paths, no hyphens)
- References validated for resolution and cycles
- Breaking changes require MAJOR version bump
- Deprecation strategy with migration paths
JSON contract and adapter examples
JSON-as-API Architecture
{
"color": {
"text": {
"primary": {
"$type": "color",
"$value": "{color.gray.900}",
"$description": "Primary text color for body content"
}
},
"surface": {
"brand": {
"$type": "color",
"$value": "{color.brand.primary}"
}
}
}
}Adapter examples
// Before: Figma export (tool-specific)
{
"@primitives": {
"$color": {
"primary": {
"$type": "color",
"$value": "{@primitives.$color.blue.500}",
"$variable_metadata": {
"figmaId": "VariableID:502:227"
}
}
}
}
}// After: VDS contract (normalized)
{
"primitives": {
"color": {
"primary": {
"$type": "color",
"$value": "{primitives.color.blue.500}",
"$extensions": {
"figma": { "variableId": "VariableID:502:227" }
}
}
}
}
}Select files instead of adding mapped layers
Some approaches add mapped collections between base and semantic layers to handle brand switching. As those collections multiply, tracing the value that renders can require a specialist.
In VDS, file selection replaces mapped layers. JSON
provides structure, folders organize each brand's values, and CSS
@layer, @import, and the cascade handle
consumption.
Brand selection happens by file list, not by mapped collections in a design tool panel. Selecting a brand folder changes the values while preserving the semantic names.
Brand file selection
tokens/
base/ # Shared scales (all brands)
color.json
spacing.json
brand-a/ # Brand A values
color.json # color.brand.primary = #0066cc
brand-b/ # Brand B values
color.json # color.brand.primary = #ff0066Mapped layer costs and brand-selection examples
Mapped layer costs
Each additional layer between base and alias creates compounding overhead:
Second naming decision: Every semantic variable now requires naming the intermediate mapped value too. Double the naming surface. Double the review scope.
Extra reference hop: Every resolution traverses one more layer. More hops, more failure points, slower builds.
Extra audit surface: Another collection to review, validate, and keep in sync across brands. Another place for drift.
Expanded decision surface: Instead of one file selection, you now manage collection modes in cramped tool panels.
Artificial complexity: Complexity that benefits specialists, not teams. Variables should be easy to reason about.
// Non-conformant: Mapped layer adds overhead
{
"mapped": {
"brand": {
"primary": { "$type": "color", "$value": "{color.blue.500}" }
}
},
"color": {
"surface": {
"brand": { "$type": "color", "$value": "{mapped.brand.primary}" }
}
}
}// Build config selects brand by source list
{
"source": [
"tokens/base/**/*.json",
"tokens/brand-a/**/*.json"
]
}If you can select files, you can switch brands. No extra collection required. One decision point. CSS cascade layers handle consumption.
/* CSS cascade layers for brand selection at consumption */
@layer base, brand;
@import "variables-base.css" layer(base);
@import "variables-brand-a.css" layer(brand);Review and resolution
- One alias hop from base is the default. Direct path. No detours.
- No extra collection to review, audit, or explain to new team members.
- The three-layer graph keeps review scope small and traceable.
- CSS
@layerand@importhandle cascade. Use the platform. - Decisions live in files and build inputs, not cramped plugin panels.
- Any engineer can read the folder structure and understand the brand switch.
Version control and build inputs
The primitives already exist. You do not need new abstraction layers:
Files are already versioned. Git tracks every change. History, blame, diff, rollback for free.
Paths are already structured.
tokens/brand-a/color.jsonis self-documenting. No second naming system required.Build tools already select files. Style Dictionary's
sourcearray. CSS@import. The selector exists.Engineers already know this pattern. Every dev understands folder structure. Not every dev wants to learn design tool panel quirks.
One source of truth. The JSON in version control is canonical. The design tool panel is a view, not the source.
Mapped layers are a workaround for tools that cannot do file selection. We have tools that can.
Validate changes before merge
VDS builds on the W3C Design Tokens Community Group specification, adding governance without reinventing the format.
Validation in CI
VDS requires validation before a change merges:
- JSON schema validation for DTCG compliance
- Naming convention checks (dot-separated, lowercase)
- Reference resolution and cycle detection
- Mode key consistency within collections
- Breaking change detection with release notes requirements
DTCG types, versioning rules, and deprecation example
DTCG 2025.10 types
{
"border": {
"default": {
"$type": "border",
"$value": {
"width": { "value": 1, "unit": "px" },
"color": {
"colorSpace": "srgb",
"components": [0.88, 0.88, 0.88],
"hex": "#e0e0e0"
},
"style": "solid"
}
}
},
"typography": {
"heading": {
"$type": "typography",
"$value": {
"fontFamily": "{font.family.primary}",
"fontSize": "{font.size.lg}",
"fontWeight": "{font.weight.bold}",
"lineHeight": 1.5
}
}
}
}Versioning and deprecation
Breaking changes are explicit. Consumers can plan upgrades:
MAJOR: Variable renamed or removed, type changed
MINOR: New variables, new modes, non-breaking additions
PATCH: Value tweaks, documentation updates
{
"color": {
"primary": {
"$type": "color",
"$value": "#0066cc",
"$deprecated": true,
"$description": "Use color.brand.primary instead"
},
"brand": {
"primary": {
"$type": "color",
"$value": "#0066cc"
}
}
}
}Where the specification ends
I publish VDS as a living governance specification informed by design systems work. It defines naming, validation, versioning, and adapter patterns on DTCG 2025.10. The intended contract outlives an individual design tool and stays in version control.
VDS is not a new file format, a runtime library, or a design system. It governs variables and their changes; it does not choose a team's design decisions. Validation happens at build time. The three-layer constraint keeps the contract explicit rather than adding another abstraction layer.
The specification describes what a conforming workflow must check. Primitree is where I implement token architecture checks, build output, and change reports. Keeping the specification and the tool separate makes each responsibility reviewable.
Project notes
DTCG
Built on W3C Design Tokens Community Group 2025.10 specification
JSON-as-API
File paths and variable names are the contract interface
3 Layers
Base, Alias, Component. No fourth layer. No extra hops.