Updated September 29, 2026 11 min read
Middle Foundations

Figma Variables vs Styles: Which Your Design System Needs

Build - structure tokens & Variables

Styles store composite values and cannot alias. Variables store single values, alias in chains, and drive modes. How to choose between them.

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/default can point at gray/50, and button/primary/bg can point at background/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

CapabilityStylesVariablesWhy it matters
Holds a composite of valuesYesNoA text Style carries family, size, weight and line height as one unit; a Variable holds one value
Holds numbers and booleansNoYesSpacing, radius, opacity and layer visibility have no Styles equivalent
Can alias another entryNoYesAliasing is what builds a primitive to semantic to component chain
Carries per-mode valuesPartialYesA Style gains modes only when a Variable is bound inside it
Supports scoping and code syntaxNoYesScoping limits where a value appears; code syntax maps a token name to code
Holds gradients, images, blend modesYesNoComposite 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/Default can export as a hex value, but the fact that it aliases gray/50 was 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.

  1. Normalise names before anything else. Variables cannot share a name and cannot contain spaces, so two Styles called Grey/50 and Grey / 50 collapse into a collision. Fix naming first, then migrate.
  2. 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.
  3. Create the Primitives collection from that inventory. Raw palette steps and number scales, no aliases, edit access restricted to system owners.
  4. 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.
  5. Rebind the components to the new Variables, then remove the orphaned Styles. Removing Styles before rebinding leaves layers pointing at nothing.
  6. 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

ProblemWhat actually happensFix before migrating
Duplicate Style namesVariables cannot share a name, so creation stops partway through the setRename duplicates to distinct paths
Spaces in Style namesVariables reject spaces, so plugins strip them and the link back to the original Style breaksConvert names to slash-separated paths
Inconsistent slash spacingGrey / 50 and Grey/50 resolve to different groupsStandardise slash spacing file-wide
Text StylesA composite text Style cannot become a single Variable - it holds several properties at onceBind 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.

Styles store a composite of values that are expressed all at once - a text Style holds font family, size, weight, and line height together. Variables store a single raw value, such as one color, one number, or one boolean, and expose one value at a time depending on the active mode. Only Variables support aliasing and modes; Styles cannot reference another entry.
Use Variables when a value needs to reference another value, switch by mode, or survive the trip into code. Aliasing is the reason: a semantic Variable can point at a primitive, which is what makes a token hierarchy possible, and Styles cannot alias at all. Variables also cover numbers and booleans, so spacing, radius, and opacity can finally be tokenized.
Variables are Figma's storage mechanism; design tokens are the platform-independent concept of a named design decision shared between design and code. A Figma Variable is one way to express a token, and it maps to code through the W3C Design Tokens Community Group format. A complete token set also includes composite tokens like shadows and typography, which Figma expresses as Styles.
Figma documents six Variable types: Color, Number, String, Boolean, Timing, and Easing. Color holds solid fills with optional opacity, Number covers dimensions and spacing, String handles text and variant switching, and Boolean drives true and false states. Timing and Easing hold animation durations and easing curves for Figma Motion, which is why older guides that list only four types are out of date.
No. A variant is a state within a component set, such as default, hover, or disabled, while a Variable is a reusable value that layers and components can reference. They connect through String and Boolean Variables, which can control which variant a prototype displays - so a Variable can drive variant selection without being a variant.
Color Styles convert cleanly because a color is already a single value, and community plugins automate that pass. Two problems stop a bulk conversion partway: Variables cannot share a name and cannot contain spaces, so duplicate or spaced Style names break case by case. Text Styles cannot convert at all, because a composite of several properties has no single-value equivalent - bind Variables into the text Style instead.
Styles export as literal values, so a generated CSS variable holds a hex code and nothing about where that value came from. Variables carry their alias chain, so an exported token file can reproduce the primitive-to-semantic relationship as well as the value. That is why the alias chain matters beyond Figma: it is the difference between code that can be re-themed and code that needs a find-and-replace.
Publish them as a library. Variables publish like components and Styles do, and any file that enables the library can read and use them, which keeps values consistent across a product. The consuming file cannot edit a published Variable, so changes belong in the source library - which is usually what you want for governance, since it keeps one file authoritative.
See all

Follow us on every platform