# Variables

Export the compiled tokens as Figma variables, and update every mode in place as the tokens change.

Mirror’s tokens reach Figma in two halves. Colors, dimensions and the singular
typography values become Figma variables, imported with Figma’s own variable
import, and the composites a variable cannot hold, meaning text styles and
effect styles, go in through a plugin we ship. This page covers the variables
half; [Styles](/figma/styles) covers the plugin. Both halves update what is
already in the file when you re-run them, and neither ever deletes anything.

Everything below describes the export built from our standard token set. The
same commands work against a token set of your own, with the collections read
off your config instead of ours; see
[Custom Tokens](/figma/custom-tokens) for what changes.

## Generating the export

```bash
pnpm mirror tokens
pnpm mirror figma
```

`mirror tokens` compiles the token source into `.maas/tokens/`, and
`mirror figma` reads that compiled output and nothing else, so the two run in
this order. The command needs the `json` platform in `options.platforms` of
`mirror.config.ts` and stops with an error naming the key without it.

The export is written to `.maas/figma/`, one directory per variable collection
with one DTCG file per mode, plus the `styles.json` payload the plugin reads.
Built from our own token set, that comes out as follows.

```
.maas/figma/
  color/base.json
  color/dark.json
  dimension/base.json
  typography/base.json
  typography/mono.json
  typography/sm.json
  styles.json
```

`styles.json` takes no part in the variable import. It is the one input of the
Mirror Styles plugin, and [Styles](/figma/styles) covers what it does.

Which collections and modes come out is stated in `figma.collections` of
`mirror.config.ts`, and the key is required. Our stock config, which
`mirror init` scaffolds, declares the three collections in the listing
above; this is its color entry.

```ts
figma: {
  collections: [
    {
      name: 'Color',
      types: ['color'],
      modes: [
        { name: 'Base', targets: ['application'] },
        { name: 'Dark', targets: ['application', 'theme/dark/application'] },
      ],
    },
  ],
}
```

`name` is the collection in Figma and the directory its mode files are
written into, `types` names the source `$type` values that belong to it, and
each mode lists the targets it reads. Typography declares `Base`, `Mono` and
`SM` modes the same way, which is why the mono theme’s file sits under
typography and not under color, and Dimension declares `Base` alone. A run
without the key fails, and the error prints a suggested roster read off your
targets, ready to paste into the config.
[Custom Tokens](/figma/custom-tokens#declaring-collections) documents the
full shape of the key.

Every value in the files is a resolved literal, with colors converted to sRGB
and rem sizes multiplied out to pixels, so no collection depends on another
being imported. Each entry includes a description naming the token path and
its authored value, so a variable in Figma traces back to the token it came
from.

Before anything is written, the command checks that every mode file of a
collection holds the identical set of variable names and types, and a
mismatch fails the run naming the collection, the mode and the missing names.
Figma creates a variable only when it appears in every file a new collection
is built from, so a hole in one file would silently drop the variable from
all of them. The output directory is cleared and rewritten on every run, so a
mode that leaves the config also leaves the disk.

## Importing the variables

The mode files go in through Figma’s own variable import rather than through
the plugin. A variable is addressed by an internal ID, and every layer and
style that uses it points at that ID, so an update has to change values
without recreating variables, and Figma’s importer is where that is handled
correctly.

To create a collection, open the Variables panel in your Figma file, create
an empty collection, and drag all of the collection’s mode files into it
together. Each file becomes one mode.

To update after a re-run, right-click the mode, choose Import mode, and pick
the regenerated file. Variables are matched by name and type, and their
values are updated under the same ID, so everything pointing at them keeps
working. Mode names take no part in the matching, so a designer who renames
`Base` to `Light` in Figma changes nothing about how updates arrive.

To adopt a theme later, import its file as a new mode of the same collection,
once.

## Names

The variable names are the token paths, slash-joined. Color names drop
`app.color.` and the `component` segment, since nearly every semantic color
lives under it, and they keep `default`, so the hover and active variables
sit next to it in the panel. Everything else drops the leading `app.` alone.

::docs-table
---
columns:
  - label: Token
  - label: Variable
rows:
  - items:
      - label: app.color.surface.bg.base
      - label: surface/bg/base
  - items:
      - label: app.color.component.primary.bg.solid.default
      - label: primary/bg/solid/default
  - items:
      - label: app.fontSize.surface.display.lg
      - label: fontSize/surface/display/lg
---
::

The import never deletes. A renamed token arrives as a new variable and
leaves the old one behind with nothing pointing at it, and removing the
orphan is a decision made in Figma rather than by the import.

## What a re-run changes

The variables and the text styles split the work. The styles are bound to the
variables, so a value-only token change is finished once the affected modes
are re-imported, and the plugin only enters when the set of styles itself
changes. That second case is covered on
[Styles](/figma/styles#what-a-re-run-changes); the rows below are the
variable half.

::docs-table
---
columns:
  - label: Change
  - label: What to do
rows:
  - items:
      - label: A token value changed
        plaintext: true
      - label: Run both commands, then update the affected modes through Import mode.
        plaintext: true
  - items:
      - label: A theme or breakpoint was added
        plaintext: true
      - label: Run both commands, then import the new file as a new mode of its collection.
        plaintext: true
  - items:
      - label: A token was renamed or removed
        plaintext: true
      - label: Nothing is removed in Figma. The old variable stays behind with nothing pointing at it; delete it by hand.
        plaintext: true
---
::

## Further reading

- [Styles](/figma/styles): the text and effect styles, and the plugin that
  writes them.
- [Custom Tokens](/figma/custom-tokens): the same export built from a
  token set of your own.
- [CLI](/overview/cli#mirror-figma): the command, and the arguments the build
  commands share.
- [Configuration](/tokens/configuration): `mirror.config.ts`, which holds
  the targets and the `figma.collections` roster the export reads.
