Figma Variables and Styles both save reusable values, but they store fundamentally different things. A Style holds a composite of values that all get expressed at once - a text Style carries font family, size, weight, and line height as one unit. A Variable holds a single raw value - one color, one number, one boolean - and exposes one value at a time per mode.
The distinction becomes a design system decision the moment you need aliases. Variables can reference other Variables, which is how a primitive feeds a semantic token feeds a component token. Styles cannot reference anything. So the choice between them is not a matter of taste: it decides whether your file can hold a token hierarchy at all, or only a list of saved looks.
This guide covers the mechanical difference, where a Styles-based file breaks down, how to migrate, and the cases where Styles really are the right answer.
For the wider architecture, our Figma design tokens guide covers Primitives, semantic layers, and naming in full, and Find Untokenized Values is the scan that catches exactly what a Styles-based file leaves behind.
In short
- Styles store composites; Variables store single values. A text Style is one unit of many properties; a color Variable is one color that can be reused anywhere.
- Only Variables support aliasing.
background/defaultcan point atgray/50, andbutton/primary/bgcan point atbackground/default- Styles can only hold a literal value. - Only Variables support modes, and modes are what make light and dark themes work without duplicated components.
- Figma documents six Variable types - Color, Number, String, Boolean, Timing, and Easing - not the four that most tutorials still list.
- Styles stay the right tool for gradients, images, blend modes, effects, and one-off text presets, and you can bind Variables inside a Style to give it modes.
Composite values versus single values
The distinction between Styles and Variables is about what they can hold, not where they appear in the interface. Figma’s own documentation describes Styles as built to hold a combination of values where all values get expressed at once, and Variables as storing single, raw values where only one value can be expressed at a time.
A color Style behaves like a stack of cards viewed from above: it can hold a solid fill, a gradient, an image, or a blend mode, and everything in the stack applies together. A Variable behaves like the same stack viewed from the side, where only the top card is visible and the visible card changes with the active mode. That is why a gradient belongs in a Style and a single hex value belongs in a Variable.
What Figma Styles and Variables can each store
| Capability | Styles | Variables | Why it matters |
|---|---|---|---|
| Holds a composite of values | Yes | No | A text Style carries family, size, weight and line height as one unit; a Variable holds one value |
| Holds numbers and booleans | No | Yes | Spacing, radius, opacity and layer visibility have no Styles equivalent |
| Can alias another entry | No | Yes | Aliasing is what builds a primitive to semantic to component chain |
| Carries per-mode values | Partial | Yes | A Style gains modes only when a Variable is bound inside it |
| Supports scoping and code syntax | No | Yes | Scoping limits where a value appears; code syntax maps a token name to code |
| Holds gradients, images, blend modes | Yes | No | Composite visual treatments have no single-value representation |
Six Variable types, not four
Figma documents six Variable types: Color, Number, String, Boolean, Timing, and Easing. Color carries solid fills with optional opacity, Number covers dimensions and spacing, String handles text values and variant switching, and Boolean controls true and false states. Timing and Easing hold animation durations in milliseconds and easing curves, and they exist to drive Figma Motion work.
If you learned Variables when only four types existed, your mental model is incomplete rather than wrong. The consequence is practical: an animation system built only from Styles has no way to express duration or easing as a token, because a Style cannot hold a millisecond value or a curve.
Why a Styles-only file cannot build a token hierarchy
A token hierarchy depends on one Variable pointing at another, and Styles break that chain entirely. Figma states plainly that Styles do not support aliasing, while any Variable can reference another Variable of the same type. That same-type constraint is worth remembering: a color Variable aliases a color Variable, and a Number Variable aliases a Number Variable. You cannot alias across types.
The token chain below shows every layer as a Variable. Primitives hold raw values with no aliases, atoms point at primitives, and the component layer points at atoms:
/* Primitives - raw values, no aliases */
gray/950 → #030712
gray/50 → #f9fafb
/* Atoms - alias a primitive, never a raw hex */
background/default → gray/50
text/primary → gray/950
/* Component layer - aliases an atom */
button/primary/bg → background/default
Replace the atoms with color Styles and the chain disappears. background/default becomes a Style holding #f9fafb directly. The relationship between the semantic name and gray/50 is gone, and no tool can recover it, because nothing in the file records that the two were ever connected. Change gray/50 and the Style does not move.
Aliasing is the single most consequential difference between the two features, and it is the reason we build our scanning and creation workflow around Variables rather than Styles. A semantic layer is only semantic while the aliases still resolve.
What the Styles-only path costs
A file built entirely on Styles still looks correct on the canvas, which is exactly why the cost stays hidden until the file meets code. The failure is not visual - it is structural, and it surfaces in four predictable places.
- Theming duplicates instead of switching. Without modes, a dark theme means a parallel set of Styles and a second set of components to maintain. Two themes become four the moment a brand variation appears.
- Numbers stay hardcoded. Spacing, radius, and opacity have no Styles equivalent, so they sit as raw values on layers and never enter a token file.
- Code generation loses the semantics. A Style named
Background/Defaultcan export as a hex value, but the fact that it aliasesgray/50was never recorded, so the generated code cannot reproduce the chain. - Coverage becomes unmeasurable. You cannot audit what was never tokenized. Every property in the file is a value without a token, and there is no way to tell a deliberate hardcoded number from one nobody noticed.
The fourth cost is the one that compounds. Manual audits miss values that match by coincidence and flag values that are intentionally unique, and they take long enough that nobody runs them often. That is why we treat an automated scan as the starting point rather than a periodic cleanup task - a machine has no trouble checking every fill, stroke, and padding value against your token set.
How to migrate a Styles-based file to Variables
A migration from Styles to Variables is mostly a naming and structure exercise, and the failures are predictable. The order below is the one that avoids creating duplicate entries you would have to clean up afterwards.
- Normalise names before anything else. Variables cannot share a name and cannot contain spaces, so two Styles called
Grey/50andGrey / 50collapse into a collision. Fix naming first, then migrate. - Inventory the values actually in use. Scan selection or the whole page to extract the colors, spacing, radii, and typography values the file really contains, deduplicated - not the values you assumed were there.
- Create the Primitives collection from that inventory. Raw palette steps and number scales, no aliases, edit access restricted to system owners.
- Create the atoms and alias them to the primitives. Every semantic entry points at a primitive - never a raw hex - using the alias icon in the value picker.
- Rebind the components to the new Variables, then remove the orphaned Styles. Removing Styles before rebinding leaves layers pointing at nothing.
- Run a coverage audit to confirm nothing was missed, and repeat the export step so code stays in step with the file.
Migration problems that stop a Styles-to-Variables conversion
| Problem | What actually happens | Fix before migrating |
|---|---|---|
| Duplicate Style names | Variables cannot share a name, so creation stops partway through the set | Rename duplicates to distinct paths |
| Spaces in Style names | Variables reject spaces, so plugins strip them and the link back to the original Style breaks | Convert names to slash-separated paths |
| Inconsistent slash spacing | Grey / 50 and Grey/50 resolve to different groups | Standardise slash spacing file-wide |
| Text Styles | A composite text Style cannot become a single Variable - it holds several properties at once | Bind Number and String Variables into the text Style instead of converting it |
The text Style row surprises most teams. Colors convert cleanly because a color is already a single value, but a text Style is a composite by design, so there is nothing single to convert it into. The correct move is to keep the text Style and bind Variables into the properties it holds, which gives the Style modes without discarding the composite.
Real questions designers ask about Variables and Styles
Four questions come up in almost every migration conversation, and each one traces back to a term being used loosely. Separating them removes most of the confusion.
What is the difference between a property and a Variable?
A property is the slot on a layer - fill, stroke, padding, corner radius, opacity. A Variable is the value you put in that slot. Properties cannot be Variables and Variables cannot be properties; the relationship is that a Variable gets bound to a property. When someone says a design is fully tokenized, they mean every property that accepts a Variable has one bound instead of a raw value.
Is a variant the same as a Variable?
No, and they operate at different levels. A variant is a state of a component - default, hover, disabled - and lives in the component set. A Variable is a value that components can reference. The two connect through String and Boolean Variables, which can drive which variant a prototype shows, so a Variable can control variant selection without being a variant itself.
What is the difference between Variables and design tokens?
Variables are Figma’s implementation; design tokens are the platform-independent concept. A token is a named design decision meant to be shared between design and code, which is why the interoperable format is the W3C Design Tokens Community Group specification rather than any one tool’s storage model. Figma Variables cover the values Figma can hold; a complete token set also needs composite tokens such as shadows and typography, which is where Styles remain in the picture.
Can you move Variables between Figma files?
Yes, by publishing a library. Variables publish the same way components and Styles do, and consuming files read them with the library’s integrity intact - which is also how cross-file consistency is maintained. The constraint to plan around is scope: a consuming file can use a published Variable but cannot edit it, so any change has to happen in the source library.
When Styles are still the right choice
Styles are not deprecated, and Figma’s own guidance is that Variables are not a replacement for them. The two features are additive, and a mature file uses both deliberately.
- Effects and shadows. Composite effect treatments have no single-value representation, so a shadow Style remains the cleanest way to apply them consistently.
- Gradients, images, and blend modes. Anything that stacks multiple values belongs in a Style, because a Variable can only express one value at a time.
- Typography presets. Keep the text Style as the unit designers apply, and bind Number and String Variables into it so it inherits modes.
- Genuine one-offs. A single illustration or an empty-state treatment that will never repeat does not need indirection.
One nuance gets missed here: modes are built for Variables, but Figma allows them to be applied to Styles as well. Bind a Number Variable for font size into a text Style and that Style inherits the mode behaviour. This is the mechanism that lets a typography system participate in theming without pretending a composite is a single value.
Audit the file before you choose
The decision between Variables and Styles is easier to make with numbers than with opinions, and a scan gives you those numbers in one pass. We scan a selection or a whole page, extract the colors, spacing, radii, typography, effects, gradients, and opacity values actually present, deduplicate them, and create Figma Variables as a Primitives to Atoms hierarchy bound to the layers that used those values.
The audits answer the follow-up question. Coverage Audit lists every property still missing a bound Variable - fills, opacity, padding, gap, radius, and stroke - with a clickable list that zooms to the layer in Figma. Find Untokenized Values surfaces the raw values with no token behind them.
Contrast Audit checks text and background pairs against WCAG ratios, which matters more once a theme can switch, because a pairing that passes in light mode can fail in dark mode. Token sets export to DTCG JSON, the interoperable format that Style Dictionary and similar pipelines consume.
You do not need to convert the whole file at once. Scanning a single page or a single component set is enough to see the shape of the problem, and the coverage number tells you whether the rest is a week of naming or a quarter of rebinding.
Final verdict - Figma Variables vs Styles
Choose Variables for anything that needs to scale, theme, or reach code, and keep Styles for composites that have no single-value equivalent. The practical test is one question: does this value need to reference another value? If yes, it must be a Variable, because Styles cannot alias. If it is a gradient, a shadow, or a text preset, it belongs in a Style - ideally with Variables bound inside it so it still participates in modes.