> ## Documentation Index
> Fetch the complete documentation index at: https://docs.livry.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Variants: One Brand's Overrides on a Theme

> A Variant holds only the token values that make one brand different. Learn how resolution works, what a Variant may not change, and why they do not move between Environments.

A **Variant** is one brand. It holds the token *values* that make it different from the Theme, and
nothing else.

```json theme={null}
{
  "color.brand.primary": "#14AE59",
  "font.body": "Inter"
}
```

That is the entire storage format — a flat map of token path to value. No tree, no types, no
descriptions, no groups.

## Why a default plus overrides

Most brands differ from your baseline in a handful of values. Storing a complete theme per brand
means every future addition to your design system has to be backfilled across every brand you serve.

With a default Theme, a Variant stores only its differences. **Add a token to the Theme and every
brand inherits it immediately**; brands that need something else override it.

## Resolution

Resolution is the Theme's document with the Variant's values overlaid, **path by path**.

<CodeGroup>
  ```json Theme theme={null}
  {
    "color": {
      "$type": "color",
      "brand":  { "$value": "#5B4DE4", "$description": "Primary action colour." },
      "link":   { "$value": "{color.brand}" }
    }
  }
  ```

  ```json Variant theme={null}
  {
    "color.brand": "#14AE59"
  }
  ```

  ```json Resolved theme={null}
  {
    "color": {
      "$type": "color",
      "brand":  { "$value": "#14AE59", "$description": "Primary action colour." },
      "link":   { "$value": "{color.brand}" }
    }
  }
  ```
</CodeGroup>

Three things to notice:

* **The structure is untouched.** The tree, the names, the groups, `$type`, `$description` and
  `$extensions` all come through exactly as the Theme wrote them. Only `$value` changes.
* **`color.link` moved too**, without being overridden, because it is an alias. That is the leverage
  — see [Tokens](/theming/tokens).
* **`$description` survived the override.** A Variant cannot change it, so the Theme's stays.

## What a Variant may not do

<Warning>
  **The Theme owns what a token *is*. A Variant owns only what it is set to.**

  A Variant cannot:

  * **add** a token the Theme does not have — the override is silently ignored, because there is
    nothing for it to apply to;
  * **rename** a token — it does not own the layout;
  * **retype** a token — `$type` is the Theme's;
  * **describe** a token — `$description` is the Theme's;
  * **remove** a token — `unset` stops *overriding* it, which returns it to the Theme's value.
</Warning>

This is why a Variant is stored as a value map rather than as a document. Storing it as a document
would mean storing a copy of the Theme's structure that was free to drift from it.

### `unset` is not "set to nothing"

```json theme={null}
{ "operation": "unset", "path": "color.brand" }
```

The path falls back to the Theme's own value. That is what "this brand no longer changes this token"
means, and it is different from overriding it with an empty value.

## Variants and Theme versions

A Variant's overrides only mean anything against a particular Theme structure, so **a Variant version
number *is* the Theme version its overrides are addressed against.**

Two consequences, both of which you will meet:

<AccordionGroup>
  <Accordion title="A Theme publish migrates every Variant automatically">
    When a Theme publishes, Livry reads what changed and corrects every Variant beneath it: keys the
    Theme renamed are renamed here, and keys it removed — or retyped past fitting — are dropped.

    **That migration writes each Variant's draft. It does not publish.** So after a Theme publish,
    expect `hasUnpublishedChanges` on Variants nobody touched. Review and publish each one.
  </Accordion>

  <Accordion title="A Variant can be published once per Theme version">
    The publish writes a version file numbered with the Theme's current version. Publishing again
    against the same Theme version finds that file already written and refuses with `409`.

    To publish a Variant change again, publish the Theme first. Pinned URLs were designed not to
    depend on this, but it is a real limit.
  </Accordion>
</AccordionGroup>

## The Theme on its own

A Theme with no Variants is not an error. It resolves to its own defaults unchanged, and is served at
the `-` Variant segment:

```text theme={null}
https://cdn.livry.dev/{environmentID}/{themeID}/-/latest/tokens.css
```

Use it as your own product's default styling, with Variants layered on for customers who have a
brand.

## Environment boundaries

<Warning>
  **Variants do not move between Environments.** One created in sandbox stays in sandbox; there is no
  promotion step that copies it to production.

  If you need to mirror brand configuration into production, script it against the
  [API](/api/variants) as part of your own release process, where you control exactly what is copied
  and when.
</Warning>

## How many

Variants per Theme are capped by your plan — 10 on Free, 100 on Pro. Creating one past the allowance
is refused with `402`. See [Plans and limits](/settings/billing).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.