Working with Variable Collections and Modes in Figma: A Complete Guide to Design Tokens
Figma variable collections are containers that group related design tokens, while modes enable multi-theme support (Light/Dark) within a single collection using the Figma Plugin API and helper scripts from the figma/mcp-server-guide repository.
This guide explores working with variable collections and modes in Figma based on the canonical reference implementation in the figma/mcp-server-guide repository. Whether you are automating design system generation or managing complex theming architectures, understanding how collections structure primitives and semantic tokens alongside mode-specific values is essential for scalable, maintainable design systems.
Understanding Variable Collections and Modes Architecture
Figma’s design token system organizes variables into collections, which act as namespaces for related tokens such as colors, spacing, or typography. Each collection contains one or more modes that store alternate values for every variable within that collection.
What Are Variable Collections?
A Variable Collection is created using figma.variables.createVariableCollection(name). According to the source code in skills/figma-generate-library/scripts/createVariableCollection.js, every new collection initializes with a single default mode automatically named "Mode 1". This default mode must be renamed to your first meaningful mode name (e.g., "Value", "Light", or "Base") before adding additional modes.
Collections support metadata tagging via setSharedPluginData using keys like dsb_key and run_id, enabling idempotent cleanup and safe re-runs of generation scripts.
Understanding Modes and Plan Limits
Modes represent contextual variations of your design tokens. As documented in skills/figma-use/references/variable-patterns.md (lines 33-34), Figma enforces plan-dependent mode limits:
- Starter: 1 mode per collection
- Professional: 4 modes per collection
- Enterprise: 40+ modes per collection
You rename the default mode using collection.renameMode(collection.modes[0].modeId, firstModeName) and add subsequent modes with collection.addMode(name).
Creating Variable Collections and Modes
The repository provides two approaches for working with variable collections and modes in Figma: direct API access and helper utilities.
Direct API Implementation
For minimal use cases, interact directly with the Figma Plugin API:
// Create a collection called "Spacing"
const spacing = figma.variables.createVariableCollection('Spacing');
// Rename the default mode to "Value"
spacing.renameMode(spacing.modes[0].modeId, 'Value');
// Tag for idempotent cleanup (optional but recommended)
spacing.setSharedPluginData('dsb', 'key', 'collection/spacing');
spacing.setSharedPluginData('dsb', 'run_id', 'run-2024-07');
Using the Helper Script
For production workflows, use the abstraction in skills/figma-generate-library/scripts/createVariableCollection.js:
// Creates collection + modes, returns modeId map
const { collection, modeIds } = await createVariableCollection(
'Color', // collection name
['Light', 'Dark'], // mode list
'run-2024-07' // optional run ID for cleanup
);
// modeIds = { Light: '12345', Dark: '67890' }
This helper automatically handles the default mode renaming, subsequent mode creation, and metadata tagging for safe re-runs.
Building a Token Architecture with Primitives and Semantics
The recommended pattern for working with variable collections and modes in Figma separates primitive variables (raw values) from semantic variables (theme-aware aliases).
Creating Hidden Primitive Variables
Primitive variables store raw values (hex colors, base spacing units) and remain hidden from designers. Implemented in skills/figma-generate-library/scripts/createSemanticTokens.js:
// Assume primColl is the "Primitives" collection with a single "Value" mode
const valueMode = primColl.modes[0].modeId;
const red = figma.variables.createVariable('red/500', primColl, 'COLOR');
red.setValueForMode(valueMode, { r: 0.95, g: 0.2, b: 0.2, a: 1 }); // raw RGBA
red.scopes = []; // hide from pickers
red.setVariableCodeSyntax('WEB', 'var(--color-red-500)');
Setting scopes = [] prevents primitives from appearing in Figma's variable pickers, ensuring designers only interact with semantic tokens.
Creating Semantic Aliases and Modes
Semantic tokens alias primitives and expose the correct modes to designers. This pattern uses figma.variables.createVariableAlias() to reference primitives per mode:
// colorColl has Light/Dark modes (modeIds from helper)
const semantic = figma.variables.createVariable('color/bg/primary', colorColl, 'COLOR');
// Light mode -> alias to red/500
semantic.setValueForMode(modeIds.Light,
figma.variables.createVariableAlias(red));
// Dark mode -> alias to another primitive (e.g., gray/800)
const gray = /* previously created primitive */;
semantic.setValueForMode(modeIds.Dark,
figma.variables.createVariableAlias(gray));
// Expose to designers with appropriate scopes
semantic.scopes = ['FRAME_FILL', 'SHAPE_FILL'];
semantic.setVariableCodeSyntax('WEB', 'var(--color-bg-primary)');
Batch Token Creation
For generating entire libraries, use the batch processor in createSemanticTokens.js:
const tokenMap = [
{
name: 'color/bg/primary',
type: 'COLOR',
values: { Light: { type: 'VARIABLE_ALIAS', id: red.id },
Dark: { type: 'VARIABLE_ALIAS', id: gray.id } },
scopes: ['FRAME_FILL', 'SHAPE_FILL'],
codeSyntax: { WEB: 'var(--color-bg-primary)' }
},
{
name: 'spacing/md',
type: 'FLOAT',
values: { Value: 16 },
scopes: ['GAP'],
codeSyntax: { WEB: 'var(--spacing-md)' }
}
];
await createSemanticTokens(colorColl, modeIds, tokenMap, 'run-2024-07');
This utility handles hex-to-RGBA conversion, aliasing, scope assignment, and metadata tagging automatically.
Managing Collections for Production Workflows
When working with variable collections and modes in Figma at scale, implement cleanup and validation patterns from skills/figma-generate-library/references/token-creation.md. The shared plugin data keys (dsb_key and run_id) allow scripts to identify and remove previous generation runs before creating new tokens, preventing duplication and enabling iterative development.
Summary
- Variable Collections are containers created via
figma.variables.createVariableCollection()that always initialize with a default "Mode 1" requiring immediate renaming. - Modes enable per-collection theming (Light/Dark) with plan limits ranging from 1 (Starter) to 40+ (Enterprise).
- Primitive variables should use
scopes = []to remain hidden, while semantic variables expose appropriate scopes and alias primitives per mode. - The
createVariableCollection.jsandcreateSemanticTokens.jshelpers in the figma/mcp-server-guide repository automate metadata tagging for idempotent, production-safe workflows. - Code syntax and scopes bridge the gap between Figma's visual interface and developer handoff in Dev Mode.
Frequently Asked Questions
What are the mode limits for Figma variable collections?
Figma enforces strict mode limits based on your plan tier: Starter teams can use 1 mode per collection, Professional teams can use 4 modes, and Enterprise teams can use 40 or more. These limits are documented in skills/figma-use/references/variable-patterns.md and apply across all collection types including color, number, string, and boolean variables.
How do I rename the default mode when creating a new collection?
When you call figma.variables.createVariableCollection(name), Figma automatically creates "Mode 1" as the default. You must call collection.renameMode(collection.modes[0].modeId, 'YourModeName') immediately after creation. The helper function in skills/figma-generate-library/scripts/createVariableCollection.js handles this automatically by accepting an array of mode names and renaming the default to the first entry before creating additional modes.
What is the difference between primitive and semantic variables?
Primitive variables store raw values (specific hex codes, base spacing units) and should have scopes = [] to hide them from designers. Semantic variables reference primitives via VARIABLE_ALIAS objects created with figma.variables.createVariableAlias(), expose relevant scopes like FRAME_FILL or GAP, and often contain per-mode values pointing to different primitives. This separation enables centralized value management while presenting a clean, theme-aware interface to designers.
How do I clean up variable collections programmatically?
Use the shared plugin data system to tag collections with unique identifiers during creation. The createVariableCollection.js script sets dsb_key and run_id metadata via setSharedPluginData(). Before generating new tokens, query existing collections using getSharedPluginData('dsb', 'key') to match previous run IDs, then remove old collections to ensure idempotent script execution and avoid orphaned variables.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →