The Problem: Variant Explosion in Branching Design Systems
When your product grows into multiple brands, themes, or platform-specific experiences, the number of design tokens can multiply uncontrollably. A typical design system might start with a few hundred tokens, but once you introduce branches for dark mode, high-contrast accessibility, white-label partners, and mobile-first views, token counts can soar into the thousands. This growth, often called variant explosion, makes maintenance a nightmare and increases the risk of inconsistency across branches.
Branching design variants are not just about color changes; they affect spacing, typography, elevation, and even component logic. For instance, a white-label partner might require a different border radius on cards, a distinct font stack, and adjusted shadow values. Without a systematic approach, teams end up duplicating token sets, each with slight modifications, leading to a tangled web of overrides and exceptions.
The core challenge is that traditional flat token schemas treat each variant as an independent set, ignoring the shared inheritance between branches. For example, a dark mode variant of a component might share 80% of its tokens with the light mode variant, yet a flat schema forces you to redefine those 80% tokens, creating redundancy. This redundancy not only bloats the design system but also introduces drift when the base token changes and the variant fails to update.
Furthermore, branching can be nested: a white-label partner might have its own dark mode, or a specific platform might have its own set of accessibility overrides. Without a recursive structure, these nested variants multiply combinatorially. A recursive token schema addresses this by allowing tokens to inherit from a parent and override only the differences, creating a tree-like structure that scales gracefully.
In this guide, we will explore how to build such a schema in Figma, leveraging token transformers and plugin capabilities. The goal is to enable teams to manage hundreds of variants without drowning in token counts. We'll look at the mathematical underpinnings, practical implementation steps, and real-world scenarios where recursion saves the day.
A Concrete Example: Multi-Brand E-Commerce Platform
Consider a SaaS company that builds an e-commerce platform used by multiple retailers. Each retailer has its own brand colors, typography, and spacing rules. Additionally, the platform supports both desktop and mobile views, plus a high-contrast accessibility mode. In a flat schema, the team would need token sets for each combination: Retailer A Desktop Light, Retailer A Desktop Dark, Retailer A Mobile Light, Retailer A Mobile Dark, Retailer B Desktop Light, and so on. For 10 retailers, 2 platforms, and 2 contrast modes, that's 40 token sets. In a recursive schema, you have a base set for the platform, then retailer overrides, then platform overrides, then contrast overrides. Each level only defines differences, reducing redundancy dramatically.
The recursive schema transforms the token count from O(n*m*k) to O(n+m+k), where n is retailers, m is platforms, and k is contrast modes. This mathematical scaling is the key advantage, but it requires a shift in how teams think about token hierarchy.
Core Frameworks: Recursive Token Inheritance and Override Patterns
At its heart, a recursive token schema is a tree structure where each token can inherit from a parent token and optionally override its value. This mirrors the cascade in CSS but applied to design tokens. The root of the tree is a base set of tokens representing the default variant. Each branch then defines a set of overrides, which may themselves be recursive.
There are three primary patterns for implementing recursion: the cascade pattern, the mixin pattern, and the composite pattern. The cascade pattern is the simplest: each variant defines a parent reference, and the token resolver walks up the tree to find the value. For example, a token like color.background.primary in a dark mode variant might inherit from the base variant but override just that one token. The mixin pattern groups overrides into reusable modules, like a "spacing-compact" mixin that can be applied to any branch. The composite pattern combines both, allowing branches to inherit from multiple parents.
In Figma, these patterns are implemented using token plugins like Tokens Studio or Design Token Manager, which support JSON-based definitions with $extends or $inherits properties. The recursive resolution happens at export time, where the plugin computes the final token values for each variant. The key is to design your token hierarchy carefully, keeping depth manageable (typically no more than 4-5 levels) to avoid performance issues and cognitive overload.
Why Recursion Works: The Mathematical Scaling Advantage
To appreciate the recursive approach, consider the combinatorial explosion. If you have 10 variables each with 3 states (like brand, platform, and contrast), a flat schema requires 10^3 = 1000 token sets. A recursive schema with 3 levels requires only 10+10+10 = 30 sets (assuming each level has 10 overrides). This is a dramatic reduction. However, recursion introduces complexity in resolution logic. The team must ensure that the resolver correctly merges overrides and that conflicts are resolved predictably (e.g., more specific branches win).
Another benefit is that changes propagate efficiently. If the base token for spacing changes, all variants that don't override spacing automatically update. This reduces maintenance effort and ensures consistency. The downside is that debugging becomes harder because the final value depends on the entire inheritance chain. Teams need tools that can visualize the resolved token tree, which some Figma plugins provide.
Execution: Step-by-Step Implementation in Figma
Implementing a recursive token schema in Figma requires careful planning, a robust token plugin, and a consistent naming convention. Below is a repeatable process that teams can follow.
Step 1: Define Your Token Hierarchy
Start by mapping out the branching dimensions. Common dimensions include brand, theme (light/dark), platform (web/mobile), and accessibility mode (normal/high contrast). For each dimension, list the possible values. Then decide the order of inheritance. For example, you might decide that platform overrides brand, and accessibility overrides platform. This ordering is crucial because it determines which override wins in conflicts.
Step 2: Create a Base Token Set
Create a JSON file with your base tokens. These should be the most generic values, often from your primary brand. For example, { "color.background.primary": { "value": "#FFFFFF" } }. This set will be the root of the tree.
Step 3: Define Override Sets
For each branch, create a separate JSON file that contains only the tokens that differ from the parent. Use a property like $extends to reference the parent set. For instance, a dark mode override might look like: { "$extends": "base", "color.background.primary": { "value": "#000000" } }. Then, a high-contrast dark mode variant could extend the dark mode set and override further.
Step 4: Use a Plugin to Resolve and Merge
Plugins like Tokens Studio can import these JSON files and resolve the inheritance chain to produce final token values for each variant. They also allow you to preview the resolved token tree, which is essential for debugging.
Step 5: Apply Tokens to Components
In Figma, use the plugin to apply tokens to component properties. Ensure that each component variant references the correct token set. For example, a button component might have a variant for "dark-mode" that pulls tokens from the dark mode override set.
Step 6: Automate Export and Documentation
Set up automated exports that generate CSS, iOS, or Android code from the resolved tokens. This ensures that developers receive the correct values for each variant without manual translation.
A common pitfall is creating too many levels of recursion, which slows down the plugin and makes the schema hard to understand. Aim for at most 4 levels. Also, avoid circular references where a token eventually extends itself.
Tools, Stack, and Maintenance Realities
Choosing the right tools is critical for a recursive token schema to work in Figma. While Figma's native token support is limited, several plugins and external tools can bridge the gap.
Plugin Options
Tokens Studio (now part of the Figma Tokens ecosystem) is the most popular choice. It supports $extends and $inherits, allowing recursive definitions. It also offers a visual tree view to inspect inheritance. Another option is Design Token Manager, which provides similar functionality but with a different UI. Both plugins export to JSON, which can be version-controlled in a repository like GitHub. For teams that need more advanced features like conditional overrides or formula-based token values, custom scripts using the Figma API might be necessary.
External Tools and Workflows
Many teams use a combination of a token repository (e.g., a GitHub repo with JSON files) and a build step that resolves the inheritance before importing into Figma. Tools like Style Dictionary or Theo can handle the resolution and generate platform-specific code. This decouples token management from Figma, making it easier to collaborate across disciplines. However, it adds complexity: changes to tokens require a commit, a build, and an import into Figma, which can slow down iteration.
Maintenance Reality
While recursion reduces token count, it introduces a new maintenance burden: keeping the inheritance chain clean. Over time, teams may accumulate orphaned override sets that are no longer used, or the inheritance order may become inconsistent. Regular audits are necessary. A good practice is to document the inheritance hierarchy in a README file and run automated tests that verify that all tokens resolve to valid values. Also, consider using a naming convention that encodes the branch path, like [email protected], to make the hierarchy explicit.
Another reality is that not all team members will understand recursion. Training and documentation are essential. Provide clear guidelines on when to create a new override set versus modifying an existing one. Establish a review process for token changes, similar to code reviews.
Growth Mechanics: Scaling Your Token Schema with Product Evolution
As your product grows, your token schema must evolve without breaking existing branches. Recursive schemas are well-suited for growth because they allow additive changes without modifying existing overrides.
Adding New Branches
When a new brand or platform is added, you simply create a new override set that extends the appropriate parent. For example, if a new retailer joins your e-commerce platform, you create a set that extends the base and overrides its brand colors. The existing retailer sets remain untouched. This additive nature makes scaling linear rather than exponential.
Evolving Existing Branches
Sometimes you need to add a new token to the base set, such as a new shadow token for a component. In a recursive schema, you add the token to the base set, and all branches automatically inherit it unless they override it. However, if a branch already has a shadow token defined, it won't inherit the new one. This can cause inconsistency if the branch's shadow token was meant to be a temporary override. To mitigate this, use a naming convention that distinguishes between permanent overrides and temporary ones, and periodically review branches to see if overrides are still needed.
Handling Deprecation
When a token is deprecated, you need to update all branches that override it. In a flat schema, this is tedious; in a recursive schema, you update the base token, and branches that don't override it automatically get the new value. For branches that do override, you must decide whether to update or remove the override. This is easier than updating every copy, but still requires attention. Using a deprecation workflow, such as marking tokens with a status property, can help track which overrides need action.
Growth also brings the risk of schema bloat. Teams may be tempted to create deep inheritance chains to handle edge cases, making the schema fragile. Establish a rule: if a branch requires more than 4 levels of inheritance, it's a sign that the schema needs refactoring. Consider flattening some levels or using mixins instead.
Risks, Pitfalls, and Mitigations
Recursive token schemas are powerful but come with their own set of risks. Awareness of these pitfalls can save your team from costly mistakes.
Over-Engineering
The biggest risk is over-engineering. Not every design system needs recursion. If you have only a few variants (e.g., light and dark mode), a flat schema with two sets is simpler and more maintainable. Recursion adds cognitive overhead and tooling complexity. Only adopt recursion when you have at least three branching dimensions or when the number of combinations exceeds 10. Start simple and introduce recursion only when the pain of duplication outweighs the complexity of recursion.
Circular Dependencies
Circular $extends references can cause infinite loops in token resolvers. For example, Set A extends Set B, and Set B extends Set A. Most plugins will detect this and throw an error, but it can still cause confusion. To avoid this, enforce a strict hierarchy: tokens can only extend from a higher level, never from a sibling or child. Use a linter in your CI pipeline to check for circular references.
Performance Issues
Deep inheritance chains (more than 5 levels) can slow down token resolution in Figma plugins, especially when dealing with thousands of tokens. Users may experience lag when switching between branches. Mitigate this by limiting depth and using caching where possible. Some plugins allow precomputing resolved token sets for each variant, which speeds up switching.
Inconsistent Override Semantics
Without clear guidelines, different team members may interpret override semantics differently. For example, should an override replace the entire value or merge with it? For tokens like shadows that are arrays, merging might be expected, but for simple color values, replacement is typical. Define clear rules: for primitive values, override replaces; for composite values (like box shadows), override merges unless specified otherwise. Document these rules in your token guidelines.
Testing and Validation
Testing a recursive schema is harder than testing a flat one because the final value depends on the inheritance chain. Implement automated tests that check that each variant resolves to expected values. For example, write a script that loads the token JSON, resolves all variants, and compares them to a snapshot. If a change breaks a variant, the test fails. This catches issues before they reach production.
Another mitigation is to use a visual regression tool that compares Figma components across variants. This ensures that token changes don't inadvertently alter the visual appearance of a variant.
Mini-FAQ: Decision Checklist and Common Concerns
Below is a structured FAQ that addresses common questions and provides a decision checklist for whether to adopt a recursive token schema.
When Should I Use a Recursive Token Schema?
- You have 3+ branching dimensions (e.g., brand, theme, platform). If you have only two dimensions, a flat schema may be simpler.
- You anticipate adding new branches frequently (e.g., new white-label partners). Recursion scales additively.
- Your token count is growing exponentially and you're maintaining dozens of near-identical token sets.
- You have a team that understands inheritance concepts and can maintain the schema.
When Should I Avoid Recursion?
- Your design system is small (fewer than 200 tokens). The overhead isn't worth it.
- Your team is new to design tokens. Start with a flat schema and migrate later.
- You don't have a token plugin that supports $extends. Manual resolution is error-prone.
- You need real-time collaboration on tokens without a build step. Recursion often requires a build pipeline.
Common Concerns
Q: Will recursion slow down my Figma file? A: It can, especially with deep inheritance. Use precomputed resolved sets and limit depth to 4 levels.
Q: How do I debug a token that resolves incorrectly? A: Use the plugin's tree view to see the resolved value and trace the inheritance chain. Add comments to your JSON files explaining why each override exists.
Q: Can I mix recursion with flat overrides? A: Yes, you can have a base recursive schema with some flat override sets for special cases. Just be consistent about the resolution order.
Q: How do I handle token aliases (e.g., a token referencing another token)? A: Aliases should be resolved after inheritance. Most plugins handle this correctly, but ensure that your resolver supports aliases across branches.
Synthesis and Next Actions
Building a recursive token schema for branching design variants in Figma is a strategic investment that pays off when your product scales across multiple dimensions. It reduces token count, simplifies maintenance, and ensures consistency across branches. However, it requires careful planning, the right tooling, and a team that understands the inheritance model.
To get started, audit your current token system. Count the number of variants you have and project how many you'll need in the next year. If the numbers are already high or growing, plan a migration to a recursive schema. Start with a small pilot, such as a single component family, and validate the workflow before rolling out to the entire design system.
Next, choose a plugin that supports $extends (like Tokens Studio) and set up a token repository with version control. Define your inheritance hierarchy and document it clearly. Train your team on the new workflow and establish a review process for token changes. Finally, set up automated testing to catch regressions early.
Remember that recursion is a tool, not a goal. If your design system doesn't need it, don't force it. But if you're struggling with variant explosion, recursion can be the key to reclaiming sanity and scalability.
Comments (0)
Please sign in to post a comment.
Don't have an account? Create one
No comments yet. Be the first to comment!