Export Variables & Styles
Complete guide to exporting tokens to Figma Variables and Styles: config.json setup, collections, modes, references, diff-id, and export flags.
What is Export
Export is the process of turning your JSON tokens into native Figma objects: Variables and Styles. After export, tokens become first-class elements of the Figma design system that can be bound to properties, published in libraries, and used across files.
What gets created
| JSON token | Figma object |
|---|---|
color | Variable (COLOR) |
dimension, spacing, sizing, borderRadius, borderWidth, opacity, number, fontSize, lineHeight, letterSpacing, paragraphSpacing, paragraphIndent | Variable (FLOAT) |
fontFamily, fontWeight, text | Variable (STRING) |
boolean | Variable (BOOLEAN) |
typography | Text Style |
shadow, effects, blur, backdrop-blur, glass | Effect Style |
fill, gradient, img | Paint Style |
grid | Grid Style |
fontStyle,strokeStyle,textCase,textDecoration,duration,cubicBezier,transition,template, andcompositiondo not produce standalone Variables during Export Variables. They are used in Apply/Generate workflows and code generation.
Rename behavior (ID-safe by default)
When you rename an already exported token path (for example sp.reg.md → sp.md) and keep the same token meaning, Export now treats it as a rename update:
- the existing Variable/Style is reused;
- its Figma
idis preserved; - bindings in components and files remain valid;
- in export statistics this change is counted as modified, not as create+delete.
If Delete orphaned variables & styles is enabled and the rename candidate is ambiguous (for example multiple old paths could map to one new path), Export uses a safe fallback:
- it defers orphan deletion for that ambiguous old path in the current run;
- keeps IDs stable instead of guessing a risky mapping;
- retries deletion automatically in a later run when the mapping becomes unambiguous.
The config.json file
config.json is the central configuration file that controls export. It defines:
- Which collections are created in Figma
- Which modes each collection has
- Which token files belong to each mode
- How collections reference each other
Full structure
{
"$schema": "sxl-studio/config",
"$version": "1.0",
"settings": {
"remBase": 16,
"autoExportOnPull": false
},
"collections": [
{
"name": "Primitives",
"enabled": true,
"hiddenFromPublishing": false,
"ref": [],
"modes": [
{
"name": "Default",
"enabled": true,
"ref": [],
"files": {
"colors.json": "enabled",
"spacing.json": "enabled",
"typography.json": "enabled"
}
}
]
}
],
"compositions": {
"outputMode": "component-set",
"files": {
"button.json": "enabled"
}
}
}
Field descriptions
Root fields
| Field | Type | Description |
|---|---|---|
$schema | "sxl-studio/config" | Schema identifier (set automatically) |
$version | string | Configuration version (defaults to "1.0") |
settings | object | Global settings |
collections | array | Array of variable collections |
compositions | object | Composition token settings (optional) |
settings
| Field | Type | Default | Description |
|---|---|---|---|
remBase | number | 16 | Base value for rem → px calculations. Must be > 0, otherwise defaults to 16 |
autoExportOnPull | boolean | false | Automatically export tokens after Git Pull |
collections[]
| Field | Type | Description |
|---|---|---|
name | string | Collection name in Figma (must be unique) |
enabled | boolean | Whether the collection is included in export |
hiddenFromPublishing | boolean | Hide the collection from library publishing |
ref | RefRule[] | References to other collections for alias resolution |
modes | ConfigMode[] | Array of collection modes |
modes[]
| Field | Type | Description |
|---|---|---|
name | string | Mode name in Figma |
enabled | boolean | Whether the mode is included in export |
ref | RefRule[] | References to other collections for this mode |
files | object | File map: { "file.json": "enabled" | "disabled" } |
compositions
| Field | Type | Default | Description |
|---|---|---|---|
outputMode | "component-set" | "separate" | "component-set" | Output format: as Component Set or separate components |
files | object | — | Composition file map |
Collections and modes
What is a collection
A Collection in Figma is a named group of variables. A typical design system has several collections:
{
"collections": [
{
"name": "Primitives",
"modes": [
{
"name": "Default",
"files": { "colors.json": "enabled", "spacing.json": "enabled" }
}
]
},
{
"name": "Semantic",
"modes": [
{
"name": "Light",
"files": { "semantic-light.json": "enabled" }
},
{
"name": "Dark",
"files": { "semantic-dark.json": "enabled" }
}
]
},
{
"name": "Component",
"modes": [
{
"name": "Default",
"files": { "components.json": "enabled" }
}
]
}
]
}
What is a mode
A mode is a collection variation. Classic examples: Light / Dark, Small / Medium / Large, LTR / RTL. Each mode has its own set of token files — the same token paths with different values.
Example: semantic-light.json and semantic-dark.json contain the same paths (text.primary, bg.surface) but with different colors.
Collection order
The order of collections in the collections array determines their order in Figma.
In the current version, destructive reorder is OFF by default:
- if Sort variables & styles is OFF, export does not perform order sync and keeps current order as-is;
- if Sort variables & styles is ON, export first tries non-destructive alignment;
- if strict collection order still mismatches and Allow destructive reorder is OFF, export keeps collections as-is and returns a warning;
- if the flag is ON and explicitly confirmed, the plugin performs a controlled
remove + recreatereorder; - if
Bind existing by nameis enabled, destructive reorder is not applied.
Note: recreating collections can change Figma IDs of those collections. Enable destructive reorder only intentionally to align order with
config.json.
Enabling and disabling
Set "enabled": false for a collection or mode to exclude it from export. Same for files — "disabled" skips the file:
{
"name": "Experiments",
"enabled": false,
"modes": [
{
"name": "Default",
"files": {
"experimental-tokens.json": "disabled",
"stable-tokens.json": "enabled"
}
}
]
}
Hiding from publishing
hiddenFromPublishing: true creates the collection but hides it from other files when using the library. Useful for base primitives that should not be exposed to library consumers.
{
"name": "Primitives",
"hiddenFromPublishing": true,
"modes": [...]
}
Cross-collection references (ref)
When one token references a token from another collection, you need to tell the plugin where to find the alias target. This is done through ref rules.
Local references
Reference to another collection in the same file:
{
"name": "Semantic",
"ref": [
{ "type": "local", "collection": "Primitives" }
],
"modes": [
{
"name": "Light",
"files": { "semantic-light.json": "enabled" }
}
]
}
If semantic-light.json contains {color.blue.500} and that token is defined in the Primitives collection, the plugin will find it thanks to ref.
Library references
Reference to a variable from a connected Figma library:
{
"ref": [
{
"type": "library",
"library": "Design System Core",
"collection": "Primitives"
}
]
}
| Field | Type | Description |
|---|---|---|
type | "local" | "library" | Reference type |
collection | string | Collection name (required) |
library | string | Figma library name (only for "library") |
mode | string | Mode name (optional) |
Reference levels
- Collection level (
collections[].ref) — applies to all modes in the collection - Mode level (
modes[].ref) — applies only to that specific mode
When resolving an alias, the plugin checks references in order: mode → collection → all local collections → libraries.
Alias resolution order
When the plugin encounters a reference {path.to.token}, it searches for the target variable in this order:
- Tokens in the current collection / current mode
- Explicit
localrefs (other collections in the config) - All other local collections in the file
- Memory from other diff-id files (by
figmaKey) - Explicit
libraryrefs (by library name and collection) - All library indexes by collection name
- All library variables by name
- Import cache
Export process
Stages
Export runs through several stages:
- Parse config.json — validate structure, check names, detect duplicates
- Collect tokens — read files from each mode, parse DTCG JSON
- Load diff-id — restore the mapping from the previous export
- Index libraries — scan local variables and connected libraries
- Export variables — loop through collections and modes: create, update, delete
- Export styles — create / update Text, Effect, Paint, Grid styles
- Save diff-id — write the mapping to plugin storage
- Cleanup — remove orphans (if
deleteOrphansis enabled)
What are "orphans"
Orphans are variables and styles in Figma that were created by a previous export but no longer exist in the JSON files. When deleteOrphans is enabled, the plugin:
- Deletes variables whose paths no longer exist in the config
- Deletes modes that are not in the config
- Deletes collections that are not in the config
- Deletes styles whose paths no longer match
When Selected Collections is used, orphan cleanup is scoped to the selected collections. Managed styles that belong to unselected collections are preserved, so a partial export does not wipe unrelated style groups. Run a full export only when you intentionally want orphan cleanup across the whole token project.
diff-id files
What they are
diff-id is a JSON file that stores the correspondence map between JSON tokens and Figma objects. It allows the plugin to:
- Determine which tokens were changed, added, or deleted
- Update existing variables without duplication
- Track collections, modes, variables, and styles
File naming
The file is created automatically on first export:
diff-id.<file-key>.json— if the Figma file key is availablediff-id.<document-name-slug>.json— otherwise
diff-id structure
{
"version": 2,
"$figmaFileName": "Design System",
"$figmaFileKey": "abc123def456",
"collections": {
"Primitives": {
"figmaId": "VariableCollectionId:123:456",
"modes": {
"Default": "123:789"
}
}
},
"variables": {
"color.primary": {
"figmaId": "VariableID:123:100",
"figmaKey": "abc123...",
"hash": "a1b2c3d4...",
"collectionPath": "Primitives"
}
},
"styles": {
"typography.heading.xl": {
"figmaId": "S:abc123...",
"hash": "e5f6g7h8...",
"type": "text"
}
}
}
How hashing works
A hash is computed for each token that includes:
- Value (
$value) - Scopes (
figma.scopes) - Code Syntax (
figma.codeSyntax) - Hide (
figma.hide) - Modify (
figma.modify)
On subsequent exports, the plugin compares hashes — unchanged tokens are usually skipped, which keeps repeat exports fast.
Additionally, alias/binding drift checks run for unchanged entries: if the target identity in Figma drifted (for example after library updates), the plugin performs a targeted rebind without forcing a full re-export.
Storage
diff-id is stored in the document's Plugin Data in Figma. The file is saved to disk when using Git integration. During tree-based serialization, variables and styles are nested in JSON by path segments (for compactness), then flattened back when read.
Tip: if export behaves incorrectly (duplicated variables, values not updating), try resetting diff-id through the plugin menu. This forces the plugin to rescan all tokens.
Export flags
The following settings are available during export:
Variable types
Filter by the type of variables to create:
| Flag | Figma type | Default |
|---|---|---|
color | COLOR | ✅ Enabled |
number | FLOAT | ✅ Enabled |
string | STRING | ✅ Enabled |
boolean | BOOLEAN | ✅ Enabled |
Disable a type to skip all variables of that type during export.
Style types
Filter by the type of styles to create:
| Flag | Style type | Default |
|---|---|---|
typography | Text Style | ✅ Enabled |
shadow | Effect Style | ✅ Enabled |
blur | Effect Style | ✅ Enabled |
effects | Effect Style | ✅ Enabled |
glass | Effect Style | ✅ Enabled |
fill | Paint Style | ✅ Enabled |
gradient | Paint Style | ✅ Enabled |
grid | Grid Style | ✅ Enabled |
border | Paint Style | ⬜ Disabled |
Notes:
imgtokens are exported through thefilltoggle.backdrop-blurtokens are exported through theblurtoggle.borderis currently not exported to Figma styles in the current runtime (kept for schema compatibility).
Export behavior options
By default, all behavior toggles are OFF.
This gives the safest baseline: stable IDs, no destructive operations, and minimal side effects.
| Option | Default | What it does |
|---|---|---|
| Apply codeSyntax & scopes | ⬜ | Applies $extensions.figma.scopes, $extensions.figma.codeSyntax, and figma.hide metadata to Variables, and updates Code Syntax blocks in Style descriptions |
| Force update all | ⬜ | Ignores hash optimization and rewrites all matched variables/styles in selected collections |
| Delete orphaned variables & styles | ⬜ | Removes managed Figma items that no longer exist in token files/config. Irreversible |
| Sort variables & styles | ⬜ | Tries to align variables and styles with JSON order non-destructively (preserves IDs and Diff-ID bindings) |
| Allow destructive reorder | ⬜ | Requires Sort variables & styles. If order still mismatches, allows controlled collection recreate to enforce JSON order (ID churn risk) |
| Bind existing by name | ⬜ | Adopts matching existing Figma variables/styles into Diff-ID to avoid duplicates on first rollout |
| Selected Collections | All | Exports only selected collections. Empty selection means all collections |
Practical examples
- Daily export (recommended): keep all behavior options OFF. You get fast diff-based updates and stable IDs.
- Line height/token value changed, but style looks stale: first try normal export; if needed, run one pass with Force update all ON, then turn it OFF again.
- JSON order changed: enable Sort variables & styles first. Enable Allow destructive reorder only if strict order is required and non-destructive sync could not align collections.
- Migrating an existing Figma file without duplicates: enable Bind existing by name for the migration pass, verify result, then turn it OFF for regular runs.
- Partial collection export with cleanup: select the target collections and enable Delete orphaned variables & styles only if you want to clean those selected collections. Styles from unselected collections stay protected.
Tip for Delete Orphans: use with caution. If you renamed a collection or mode in the config, the plugin will treat the old name as an "orphan" and delete it. It's better to export first without this flag, verify everything is correct, then run with
Delete Orphans.
When to enable each option
| Option | Enable when | Keep disabled when |
|---|---|---|
| Apply codeSyntax & scopes | You intentionally sync publishing metadata from token files | You only want value updates and want to avoid metadata churn |
| Force update all | After migrations/manual edits, or when you need a one-time full refresh | Normal daily export runs |
| Delete orphaned variables & styles | You confirmed removed paths should be physically deleted from Figma | During refactors/renames before final verification |
| Sort variables & styles | JSON order changed and you want non-destructive align for variables and style folders/items | Order is already acceptable, or not important |
| Allow destructive reorder | Strict JSON order is mandatory and non-destructive order sync did not converge | ID stability is critical |
| Bind existing by name | First rollout into files that already contain compatible Figma variables/styles | You want strict isolated creation from current token source only |
Flag combinations (recommended)
| Combination | Toggles | What you get |
|---|---|---|
| Daily safe diff export | Apply codeSyntax & scopes = OFF, Force update all = OFF, Delete orphaned... = OFF, Sort variables & styles = OFF, Allow destructive reorder = OFF, Bind existing by name = OFF | Fast export, only changed values/styles are updated, minimum Publish churn |
| Metadata sync pass | Apply codeSyntax & scopes = ON, others OFF | Updates scopes/codeSyntax/hide metadata without forcing full value rewrite |
| Order alignment (safe) | Sort variables & styles = ON, Allow destructive reorder = OFF, others usually OFF | Best-effort JSON order alignment for variables + styles with ID preservation |
| Strict order migration | Sort variables & styles = ON, Allow destructive reorder = ON (explicit consent) | Enforces collection order when safe pass cannot converge; may churn collection IDs |
| Brownfield adoption | Bind existing by name = ON, Force update all = OFF, Allow destructive reorder = OFF | Reuses matching local variables/styles, avoids duplicate creation during first migration |
| Recovery/full refresh | Force update all = ON (temporary), others case-by-case | Rewrites all matched items; useful after manual edits or stale state |
Figma Styles
How styles are created
Styles are created from composite tokens. For multi-modal collections, style values are taken from the first enabled mode.
| Token type | Figma style type |
|---|---|
typography | Text Style |
shadow | Effect Style |
effects | Effect Style |
blur | Effect Style |
backdrop-blur | Effect Style |
glass | Effect Style |
fill | Paint Style |
gradient | Paint Style |
grid | Grid Style |
Style naming
The token path is converted to a style name by replacing dots with slashes:
- Token
typography.heading.xl→ Styletypography/heading/xl - Token
shadow.card.md→ Styleshadow/card/md
Code Syntax in styles
When the Apply Code Syntax & Scopes flag is enabled, figma.codeSyntax values are added to the style description as a text block. This lets developers see the correct syntax directly in the style's properties.
Destructive actions: deleting collections and style groups
The Destructive actions panel inside the Export window is split into two sub-blocks — Collections and Styles. Both support:
- Search by name (collection or style group).
- Multi-select by clicking individual rows. By default, all items are
selected, so the button reads
Delete all variable collections/Delete all styles. As soon as you uncheck anything, the button switches toDelete N selected collection(s)/Delete N selected group(s). - The two global buttons stay available — keeping every row selected is
equivalent to the old
Delete All …behaviour.
Collections
- Lists every local variable collection in the current Figma file with its variable count and number of modes.
- Delete everything at once, or any subset.
- On delete:
- Collections are removed from Figma (variables bound to layers lose their bindings).
- Only matching entries are removed from
diff-id.<fileKey>.json(collections[name],variableswithcollectionPath = name, and any linkedcompositions). - If the resulting
diff-idis empty, the file is marked for deletion on Git (the push indicator will show it as a removed file).
Styles
- Lists style groups, grouped by the first segment of the style name. For
example,
w-mylib/typography/body,w-mylib/fill/brandandlegacy/shadow/cardcollapse into groupsw-mylibandlegacy. - Each row shows a breakdown by style kind (
paint / text / effect / grid) and the total count. - Delete all groups at once, or any subset.
- On delete:
- All local styles whose name starts with the selected prefix (followed by
/, or matching exactly) are removed from Figma. diff-id.styles[path]entries whose first segment matches one of the deleted groups are purged.- If
diff-idbecomes empty after purging, the file is marked for Git deletion, same as the Collections block.
- All local styles whose name starts with the selected prefix (followed by
Bug fix
Previously Delete All Collections / Delete All Styles could leave stale
diff-id references after bulk deletion. As a result, binding new tokens to
layers after a deletion could restore variables that were expected to stay
removed. The current release:
- Always updates
diff-idcorrectly (partial or full clear). - On full clear, flags
diff-id.<fileKey>.jsonfor deletion so it disappears from the Git remote on the next push. - Clears stale references immediately after deletion — no more "ghost" variables reappearing.
Warning: all operations inside the Destructive actions panel are irreversible. Before a bulk delete, save a version of the Figma file and commit your current token state to Git.
Full config.json example
A typical configuration for a design system with primitives, semantic tokens, and component tokens:
{
"$schema": "sxl-studio/config",
"$version": "1.0",
"settings": {
"remBase": 16,
"autoExportOnPull": false
},
"collections": [
{
"name": "Primitives",
"enabled": true,
"hiddenFromPublishing": true,
"modes": [
{
"name": "Default",
"enabled": true,
"files": {
"core/colors.json": "enabled",
"core/spacing.json": "enabled",
"core/typography.json": "enabled",
"core/effects.json": "enabled"
}
}
]
},
{
"name": "Semantic",
"enabled": true,
"ref": [
{ "type": "local", "collection": "Primitives" }
],
"modes": [
{
"name": "Light",
"enabled": true,
"files": {
"themes/light.json": "enabled"
}
},
{
"name": "Dark",
"enabled": true,
"files": {
"themes/dark.json": "enabled"
}
}
]
},
{
"name": "Components",
"enabled": true,
"ref": [
{ "type": "local", "collection": "Semantic" },
{ "type": "local", "collection": "Primitives" }
],
"modes": [
{
"name": "Default",
"enabled": true,
"files": {
"components/button.json": "enabled",
"components/input.json": "enabled",
"components/card.json": "enabled"
}
}
]
}
],
"compositions": {
"outputMode": "component-set",
"files": {
"compositions/button.json": "enabled",
"compositions/card.json": "enabled"
}
}
}
In this example:
- Primitives — base values (colors, spacing), hidden from publishing
- Semantic — has two modes (Light / Dark), references Primitives
- Components — component tokens, references both Semantic and Primitives
Auto-export after Git Pull
Set autoExportOnPull: true in settings to make the plugin automatically export tokens after every Git Pull.
Auto-export uses the current runtime defaults:
- variable types: all enabled (
color,number,string,boolean) - style types: enabled (
typography,shadow,blur,effects,glass,fill,gradient,grid),borderdisabled - behavior flags: all OFF (
Apply codeSyntax & scopes,Force update all,Delete orphaned...,Sort...,Allow destructive reorder,Bind existing by name)
{
"settings": {
"autoExportOnPull": true
}
}
More about Git integration in Git — Integration.
Tips and common issues
Variables are duplicated
- Check if diff-id was reset. Enable Bind existing by name so the plugin adopts existing variables/styles by name.
Values are not updating
- The hash might not have changed. Enable Force Update All to force a full update.
Aliases are not resolving
- Check
refin the config — is the collection containing the target token specified? - Make sure the file with the target token is
"enabled".
Collections keep getting recreated
- Check Allow destructive reorder:
- OFF → collections should not be recreated (you should only see a warning);
- ON → recreation is allowed after confirmation.
Related sections
- Tokens Overview — general tab structure
- Scopes & Code Syntax — visibility and code settings
- Tokens to Code — code generation from tokens
- Composition — component generation from JSON
- Git — Integration — sync through Git