Tokens

Exporting variables and styles

How Figma variables and styles are created from token JSON: collections and modes in Collection Settings, the Export to Figma window, export settings, reading the result, re-exporting without duplicates, references between collections and libraries.

Export variables & styles creates and updates Figma variables and styles from the token files. Simple tokens become variables: Color, Number, String, Boolean, Timing and Easing. Composite tokens become styles: paint, effect, text and grid. You can export as often as you like: the plugin remembers which variable belongs to which token and updates it instead of creating it again.

Before the first export: collections and modes

Figma variables live in collections, and a collection can have several modes, for example Light and Dark. Which token files go into which collection and mode is defined by config.json in the token folder. It is easier to edit in the Collection Settings window, the button at the bottom of the file tree.

Collection Settings: groups, the collection list with mode and file counts, buttons to create a group and a collection.

In the window you can:

  • create a collection with the Collection button and a mode inside it, and assign files to the mode;
  • drag collections and modes to change their order in the configuration; this does not move existing objects in Figma;
  • disable a collection, mode or file without removing it from the configuration;
  • add a reference to another collection or a library to resolve aliases;
  • combine collections into groups: a group corresponds to a separate Figma file that receives its own part of the tokens, for example Core and Components.

The same config.json in JSON:

JSON
{
  "$schema": "sxl-studio/config",
  "$version": "1.0",
  "settings": { "remBase": 16, "autoExportOnPull": false },
  "collections": [
    {
      "name": "Primitives",
      "hiddenFromPublishing": true,
      "modes": [
        { "name": "Default", "files": { "colors.json": "enabled", "spacing.json": "enabled" } }
      ]
    },
    {
      "name": "Semantic",
      "ref": [{ "type": "local", "collection": "Primitives" }],
      "modes": [
        { "name": "Light", "files": { "semantic-light.json": "enabled" } },
        { "name": "Dark", "files": { "semantic-dark.json": "enabled" } }
      ]
    }
  ]
}
FieldMeaning
settings.remBaseThe base size for converting rem, em and percentages to pixels, 16 by default. A number or a token reference "{core.font.base}"; set in the export window, field rem base
settings.autoExportOnPullRun the export automatically after every Pull from Git
collections[].nameThe collection name in Figma, must be unique
collections[].enabledfalse excludes the collection from export
collections[].hiddenFromPublishingThe collection is created but not published in the library. Handy for primitives
collections[].refWhere to look for the targets of references from another collection, see below
modes[].name, modes[].enabledThe mode name in Figma and whether it is enabled
modes[].filesThe mode's files with the status enabled, disabled or source

Collections are exported in dependency order: a collection that references another local collection in ref is processed after it, whatever their order in config.json, so a first export into an empty file completes in a single run. New collections still appear in the Variables panel in the order of your config.

A file with the source status creates no variables itself: its tokens take part in formulas and in working out values and types. A pure {path} reference to a token that exists only in a source file is not exported on its own: this Figma file has no variable for it, so the token is skipped with the reason alias target … not found while the rest is exported. If the target is a library variable, declare a ref of type library on the collection, see below.

Files of different modes hold the same token paths with different values: text.primary in semantic-light.json and in semantic-dark.json. If a mode lacks a token, the variable is still created and Figma supplies the value for that mode; such gaps are listed in the export report.

How to export

  1. At the bottom of the tree press Export variables & styles. The Export to Figma window opens with four collapsible blocks: Collections, What to export, Export settings and Delete variables & styles. The list and the Export button appear once the saved settings have loaded, usually instantly.
  2. In the Collections block tick the collections. The header checkbox selects all, the Filter by name… field searches by name, and the Show selected only switch keeps only the selected ones in the list. A pinned Selected: N of M line above the list names the selected collections.
  3. In the What to export block keep the variable and style types you need enabled.
  4. Change Export settings if needed; a regular export needs no changes.
  5. Press Export. The line at the bottom of the window shows how many collections and types are selected.

While the export runs, the notification shows its progress: a bar, an "N / total" counter and the current stage. The Cancel export button stops the run: the plugin finishes the current variable, saves the ledger for what was written, skips deletions, reorder and styles, and shows Export cancelled with the created and updated counts. The next export after a cancel continues from the same place.

The Export to Figma window: the Collections section with search and collection groups.

Variable and style types, the start of the export settings.

After the export open the Variables panel in Figma: the collections, modes and variables appear there, and the styles in the styles panel. A repeated export updates only what changed in JSON or was changed by hand in Figma.

Types

SectionSwitches
VariablesColor, Number, String, Boolean, Timing, Easing
StylesFill (including images), Gradient, Typography, Blur (both blur kinds), Shadow, Effects, Glass, Grid

All switches are on by default. Turn a type off to skip it entirely, for example to export only variables without styles.

Export Settings

SettingWhat it doesWhen to enable
Apply codeSyntax & scopesWrites scopes, code syntax and the hide flag from $extensions to Figma, plus the Code Syntax block in style descriptions. Off by default. When these settings were changed by hand in Figma, they return to the JSON if Force update all is on together with itTurn it on when these settings should be updated together with the values
Force update allBrings the Figma file to exactly what the JSON defines without changing identifiers: re-checks every variable and style and deletes everything the enabled JSON does not define. Asks for confirmation before deleting. Details belowWhen the Figma file must fully match the repository
Delete orphaned variables & stylesDeletes only what SXL exported earlier and what no longer exists in JSON, inside the selected collections and selected types. Never touches hand-made objects. Asks for confirmation before deleting. IrreversibleWhen renames and deletions in JSON are final and Figma should match them
SortArranges local styles and style folders in source order, preserving their identifiers and bindingsWhen the order of styles in the token files has changed

Ready-made combinations:

  • Daily export: everything default. Variables and styles are added and updated, nothing is deleted.
  • Tidy the order: Sort on, the rest default.
  • Sync deletions: Delete orphaned variables & styles on for one run. Only what SXL exported and what no longer exists in JSON goes away.
  • Bring the file to the repository: Force update all on for one run, then turn it off. The plugin shows the list of deletions and waits for confirmation.

Sort never deletes or recreates objects. Figma lets plugins move existing styles and style folders, but does not provide a way to reorder existing collections, modes or variables. Reordering them in Collection Settings or JSON therefore does not rearrange them in Figma. Figma controls the final display order. Set the order of existing collections, modes and variables manually in Figma.

Diff-ID

Below the switches of the Export settings block sits the Diff-ID sub-block: the plugin's memory of which Figma object belongs to which token. These actions do not run an export; the confirmation is asked in a plugin window.

ActionWhat it does
Clean up Diff-ID, the Clean up buttonRemoves records of generated components that no longer exist in Figma: those replaced by a newer copy and those that have no composition JSON. The same happens automatically on an export with Delete or Force. The same button is in the Local Workspace window, the Workspace tools section
Reset Diff-ID for one collection…, the Collection list and the Reset… buttonForgets the ids of one collection. The next export re-links its variables by name; renamed variables are created again
Reset Diff-ID…, the Reset… buttonForgets every id of this Figma file. The next export re-links variables and styles by name; renamed objects are created again and composition links are lost. Nothing in Figma changes until that export

What is updated and what is deleted

Every export, with any settings, returns to the JSON whatever was changed by hand in Figma: collection, mode, variable and style names, variable values and style content. Identifiers are kept, so layer bindings are not lost.

SettingsWhat the export does
Delete and Force offAdds and updates variables and styles. Deletes nothing; records in the diff-id service file are only added and updated
Delete orphaned variables & stylesAdditionally deletes what SXL exported earlier (it is recorded in diff-id) and what no longer exists in JSON, inside the selected collections and the selected variable and style types. A collection or mode removed from the configuration counts as selected. Never deletes hand-made objects, and never deletes collections, modes and files that are switched off in the configuration
Force update allBrings the Figma file to exactly the JSON without changing identifiers. Checks every object; an identical value is not rewritten, so on an already synchronized file the result is 0 created, 0 updated, 0 deleted. Deletes everything the enabled JSON does not define: leftovers of earlier exports, hand-made collections, modes, variables and styles, and whatever is defined only by collections, modes and files switched off in the configuration. Records of deleted objects are dropped from diff-id

Limits of Force update all:

  • When only part of the collections is selected, cleanup happens inside the selected ones only. Whole foreign or switched-off collections and foreign styles are deleted only when all collections are exported; the list shown before deletion says what was left unchecked.
  • In a file that has no diff-id yet, Force does not delete hand-made objects: the first export connects existing objects by name.
  • Styles used by compositions are never deleted, whatever the settings.
  • Library objects and types switched off in What to export are never touched.

Deletion confirmation

When an export is going to delete something, it first analyses the file without changing anything and shows a grouped list in the notification:

GroupContents
Removed from JSON (tracked)What SXL exported earlier and what no longer exists in JSON
Foreign — not created by SXLHand-made objects, with Force update all only
Disabled in configWhat is defined only by switched-off collections, modes and files, with Force update all only
KeptWhat stays, with the reason

Two buttons sit under the list: Delete N objects and export and Cancel export. Cancel changes nothing. Only what was in the confirmed list is deleted: an object that became removable after the confirmation stays, and the export names it in a warning. When there is nothing to delete, there is no prompt. The automatic export after Pull never deletes and never asks.

An export with Delete or Force enabled also forgets the Diff-ID records of generated components that are gone. A record is forgotten only when the component is not in the Figma file and the workspace has no composition JSON it was created from. While the JSON exists, the record stays: after a restore from version history Apply finds the component again, and a new Generate retires the old record by itself. The plugin does not learn about a deleted component at the moment of deletion; the check runs on an export with Delete or Force and on the Clean up Diff-ID button; Generate and Apply forget no records. In the list such records are shown as informational rows marked Diff-ID: "Forget the Diff-ID record of component "X": it no longer exists in Figma and has no composition JSON". They are not counted among the objects to delete and do not trigger the prompt on their own: nothing is deleted from the Figma file. The records are forgotten only after a successful export; on cancel, on an error or with Delete and Force off they stay. In the export result this is an informational entry, not a warning.

For agents through Bridge 1.11 and newer: preview_export_variables returns the same list without writing to the file, with the component records to forget in deletionPlan.forgottenCompositionRecords[] (fields rootId and name), and an export_variables call that needs to delete something requires confirmDestructive: true; without it nothing changes.

Destructive actions

The block at the bottom of the window deletes whole variable collections and style groups from the Figma file. Both lists have search and multi-select; the button reads Delete all … or Delete N selected …. Deletion is irreversible: variables bound to layers lose their bindings. Save a Figma file version and commit the tokens before a mass deletion.

Reading the result

The Variables panel in Figma after an export: a collection with the Light and Dark modes and the color, radius and space groups, as in the token files.

After the export the plugin shows a notification with a headline:

HeadlineMeaning
Export completeEverything was exported
Export completed with N notice(s)The export passed with remarks, for example missing mode cells or a token kept as custom
Partial exportSome variables or styles were not exported. Expand Details to see which and why
Export failedThe export stopped and nothing changed. The reason is in the details
Export cancelledThe export was stopped with Cancel export. The subtitle says how many variables were written before the stop

Copy all copies the whole report, Retry runs the export again. One token's error does not stop the others: a wrong value, an unresolved reference or an incompatible type skips only that token, and the report names its path.

Notices and errors are listed as items: a severity glyph (a red cross for an error, a yellow triangle for a notice, a grey “i” for an informational line), errors first, then notices. An item may carry a collection or path label and the number of affected variables or styles (×N), with the recommendation (“→ what to do”) under it; a recommendation shared by several items is shown once above the list. A list longer than eight items collapses behind Show N more.

Numbers and formulas in style fields

Numeric style fields accept formulas, for example "{dim.px} / 3". These are the shadow, blur and effects fields, the grid count, gutterSize, sectionSize and offset, and the typography fontSize, lineHeight, letterSpacing, paragraphSpacing, paragraphIndent and listSpacing. The result is computed and written as a number, and the report gets a notice: Figma cannot bind a formula to a variable, a field holds one variable at most. To keep the link, move the formula into a separate token and reference it. A formula with an unknown operand skips that style with the reason, the others are exported.

Literal numbers in styles accept the same units as numeric tokens, see Dimension. em in lineHeight and letterSpacing is relative to the font size of the style: 1.5em is 150 %, 0.02em is 2 %.

The glass fields lightIntensity, refraction, dispersion and the noise fields opacity, density hold a fraction from 0 to 1. A reference to an opacity token in them keeps its fraction: 0.48 stays 0.48.

A style that the export found in the file by name and connected is reported as updated, not created.

Re-exporting without duplicates

When a style (text, fill, gradient, shadow, blur or grid) references a variable that does not exist in Figma yet (for example its collection has not been exported), the style is created with a literal value and the notification lists the fields and variables in a notice. Export the collection with those variables and run an ordinary export again: the bindings are restored automatically, the style ID and its consumers are kept, Force update all is not needed.

A fill layer whose colour is bound to a variable can carry its own opacity: the export verifies the written value and repeats the write when needed, so the opacity is right after the first export. Figma does not keep a blend mode on such a layer — the export leaves NORMAL and adds a notice naming the layer; use a literal colour on the layer to keep the blend mode.

The plugin keeps the link between tokens and the variables of this Figma file in the service file diff-id.<file key>.json next to the tokens. Thanks to it:

  • a value change updates the same variable;
  • renaming a token in JSON renames the variable when the replacement can be proven unambiguously;
  • a token deleted from JSON does not delete the variable until Delete orphaned variables & styles or Force update all is on;
  • references between variables are preserved.

The file is synchronized through Git together with the tokens: do not edit or delete it by hand, and if you use Prettier, add diff-id.*.json to .prettierignore. If the link is lost, for example after copying the Figma file, a regular export finds the single matching variable with the same name and type and reconnects it. Ambiguous matches are never picked at random; the plugin reports them.

Reset Diff-ID… in the Diff-ID sub-block of the Export window breaks the link for the whole file, and Reset Diff-ID for one collection… in the same place does it for one collection. The variables and styles in Figma themselves do not change. The next export creates no duplicates: it reconnects existing variables by name and type, and styles by name and kind, and records their identifiers. Rarely needed, for example when the service file no longer matches the Figma file.

References between collections and libraries

A token may reference a token from another collection: {color.blue.500} in a semantic collection points to a primitive. For the export to find the target, the collection needs a ref entry:

JSON
{ "name": "Semantic", "ref": [{ "type": "local", "collection": "Primitives" }] }

For variables from a linked Figma library give the library and collection names:

JSON
{ "ref": [{ "type": "library", "library": "Design System Core", "collection": "Primitives" }] }
FieldValue
typelocal for a collection of this file, library for a library
collectionThe collection name
libraryThe Figma library name, library only
modeThe mode name, optional

A reference is set for the whole collection or for one mode. A library reference is an exact address: the plugin looks for the variable only in the named library and collection and never substitutes a similar one from elsewhere. The library must be linked to the file.

Declare a ref for every collection whose tokens are referenced, even when that collection is exported in the same run. Without it, a target that does not exist yet in the current export may be found in a published library through the diff-id memory of other files: the variable then aliases the library, and only the next export rebinds it to the local variable.

Reference compatibility is checked by the Figma variable kind: number may reference borderWidth because both become Number variables, while a reference from number to color is skipped with a warning.

Automatic export after Pull

If config.json has "autoExportOnPull": true, the plugin exports tokens right after every Pull from Git with the default settings: all types on, export settings off, including Apply codeSyntax & scopes. Such an export never deletes anything and never asks for confirmation.

If something does not work

What happenedWhat to do
Variables are duplicated after exportThe link is lost or ambiguous: two variables with one name. Delete the extra one in Figma and export again
A value did not updateExport with Force update all. If it is going to delete something, it first shows the list and waits for confirmation
A reference does not resolveCheck the collection's ref, the exact library and collection names and the status of the file with the target: for a pure reference the target must be in an enabled file or in a library from ref, a source file alone is not enough
Collections, modes or variables did not move after SortFigma does not expose this operation to plugins. Sort changes only the order of styles and style folders
A token was kept as custom and not exportedThe value resembles no type. Set $type explicitly
Export does not start in Local WorkspaceWriting the Diff-ID service file needs an existing file in the folder. Do the first export from a Git source or check that Bridge is active