Architecting Figma Themes for Automated Handoff
Article content
This is Part 4 of the The Design-to-Code Loop: 2026 Edition series (7 posts on closing the gap between Figma and production code).
The Figma File That Can't Be Automated
You set up the CI pipeline. The GitHub Action is ready to pull tokens. You trigger the sync, and get back a flat list of hex values with names like color 12, Untitled Variable, and bg/FINAL-v3. The pipeline fails gracefully, and a designer has to manually QA every colour change.
The bottleneck isn't the tooling: it's the Figma structure upstream. A design file built without automation in mind will always require human intervention before handoff. This post covers how to structure Figma variables so that automated pipelines actually work.
The Hierarchical Token Strategy
The most automation-resilient design systems use a three-tier hierarchy for Figma Variables, and the reason it resists automation failures specifically is that each tier has exactly one job, so a token transform script never has to guess what a given variable is for.
- Primitives (Tier 1): Raw values like
palette-blue-500orspacing-16. These are never used directly in components, only referenced by the tier above. A component that binds directly to a primitive is the single most common source of "unmatched hex value" errors in a token export, because primitives carry no semantic meaning a transform script can map to a purpose. - Semantic (Tier 2): Context-based tokens like
color-bg-primaryorspacing-layout-md. These map back to Primitives and are the "workhorses" of the system: the tokens designers actually pick from when building a screen, and the tokens a theme switch (light to dark) operates on by swapping which primitive each semantic token points to. - Component-Specific (Tier 3): Tokens for specific high-stakes components, e.g.,
btn-primary-bg. These map to Semantic tokens and exist specifically for the handful of components (primary buttons, form inputs, alerts) where a designer needs to override the semantic default without breaking the chain back to primitives.
Structuring Figma Collections
To enable automation, your Figma Collections must be organized for exportability, not just visual convenience. A "Collection-per-Domain" pattern keeps the export mapping predictable:
- Domain: Core (Primitives) - Locked to designers to prevent accidental changes; only a design system owner should be able to edit this collection, the same way only a small number of engineers should have write access to a shared token repository.
- Domain: Light/Dark (Semantic) - Different modes for different themes, structured so a mode switch changes exactly which primitive each semantic token resolves to, not the semantic token names themselves.
- Domain: Device (Platform) - Scaling variables for Desktop vs. Mobile, kept separate from color/theme modes so a responsive spacing change doesn't accidentally get bundled into a theme export.
Exporting Design Tokens
With the right structure, you can use tools like the Figma API (and specifically the getVariablesAsync method) to pull these tokens directly into your repository.
// Example: Modern 2026 Variable Fetching Logic
import { FigmaAPI } from '@figma/sdk';
async function syncFigmaTokens() {
const fileKey = process.env.FIGMA_FILE_KEY;
const variables = await FigmaAPI.getLocalVariables(fileKey);
// Group by collection and mode
const tokens = variables.reduce((acc, variable) => {
const { name, valuesByMode } = variable;
// Processing logic for themes...
return acc;
}, {});
return tokens;
}With this structure in place, a designer changing brand-color in Figma flows through the sync pipeline (webhook, fetch, transform, PR) covered in the Figma-to-GitHub automation post and lands in your React app's theme as a normal, reviewable pull request, not an instant, unreviewed change. The point of the three-tier structure is that this pipeline can run at all: an unstructured file forces a human to manually interpret every changed value, which is the exact bottleneck automation is supposed to remove.
Step-by-Step Instructions: Setting up your Figma Engine
- Define Variable Collections: Group variables by intent (e.g., "Colors", "Spacing", "Typography"), matching the three-tier hierarchy above rather than an ad-hoc grouping that made sense for one file but won't generalize.
- Create Multi-Modes: Add modes for "Light", "Dark", and high-contrast directly in your semantic collection, so a mode switch is a single toggle rather than a set of manually-maintained duplicate token sets.
- Use Scoping: Use Figma's variable scoping to restrict certain variables to specific properties (e.g., only allow "spacing" variables for padding and gap), which prevents a designer from accidentally binding a spacing token to a color property, a mistake that's easy to make and hard to spot in a visual review.
- Validate via Linting: Use Figma's built-in Design Linting to catch hard-coded values before they reach the export step. Catching a stray hex value at the design stage costs a few seconds; catching it after it's synced into a production PR costs a review cycle.
Debugging a Broken Export
When the pipeline fails or produces garbage tokens, the fix is almost never in the export script. Work backward through three checks before touching code: first, open the Figma file and confirm every color, spacing, and radius value referenced by a component is bound to a variable, not a hardcoded literal, since a literal has no name for the transform to use. Second, check for orphaned variables, ones created and never referenced by any component, which often indicates a rename happened in the UI without updating the underlying variable, leaving two variables where there should be one. Third, verify collection and mode names in Figma exactly match what your transform script expects; a mode renamed from "Dark" to "Dark Mode" for readability will silently break a script that pattern-matches on the literal string "Dark". All three are design-file hygiene issues, not pipeline bugs, and no amount of defensive code in the sync script substitutes for fixing them at the source.
Conclusion
Architecting your Figma files with a code-first mindset is what makes automated handoff work at all. This week, pick your most-used component and trace every value it uses back to a primitive: if any value doesn't resolve to a named token, that's the specific gap breaking your automation, not a general "the pipeline needs work" problem.
Next in the series: The Automation Pipeline: Figma to GitHub → Your Figma file is now structured for automation. Next: building the pipeline that turns a Figma publish into a GitHub PR without anyone pressing a button.
Sources & References
- Figma Developers Hub: Variables API — official reference for reading and writing Figma variables programmatically
- Dan Mall — designer and consultant writing on design systems process
- W3C Design Tokens Community Group (DTCG) — cross-tool design token specification drafts
- Spotify Design: Engineering at Scale — case study writing on design systems at large-team scale
Suggested Reading
Architectural Note: Research, drafting, and code for this post were augmented by Gemini (Google DeepMind), directed and verified by Maas Mirzaa. How this workflow works →