# Variants

Sell a product in colors and sizes, each variant with its own price and stock, and show the one the shopper filtered for.

A [variant](/docs/reference/glossary#variant) is one buyable version of a product, such as the Aska sofa in grey or in sage (Salbei). Each variant carries its own options, price and stock, and the product holds what they share:

```json title="tests/fixtures/home/catalog.jsonl, SOFA-ASKA-2 (trimmed)"
{
    "type": "product",
    "id": "SOFA-ASKA-2",
    "title": { "de": "Aska 2-Sitzer-Sofa aus Samt", "en": "Aska two-seater velvet sofa" },
    "categories": ["wohnen/sofas"],
    "attributes": { "seats": 2, "width": "164 cm", "upholstery": "Samt" },
    "varies_by": ["color"],
    "variants": [
        {
            "id": "SOFA-ASKA-2-GRAU",
            "attributes": { "color": "Grau" },
            "price": 749.0,
            "availability": "in_stock",
            "stock": 12
        },
        {
            "id": "SOFA-ASKA-2-SALBEI",
            "attributes": { "color": "Salbei" },
            "price": 749.0,
            "sale_price": 649.0,
            "availability": "in_stock",
            "stock": 4
        }
    ]
}
```

`varies_by` names the attributes the variants differ by, and no two variants share the same values of them. A product without variants is its own single variant, with its offer on itself. An export with one row per variant, such as a CSV file, groups its rows into products by a parent column ([Importing and mapping](/docs/importing)).

**Reference:** [`varies_by`](/docs/reference/catalog/entity#varies_by) · [`variants`](/docs/reference/catalog/entity#variants)

## Attributes that differ per variant

An attribute at `level: variant` may differ between a product's variants, such as the home store's color and size:

```json title="tests/fixtures/home/attributes.json (trimmed)"
{ "attributes": [{ "code": "color", "type": "option", "level": "variant" }] }
```

Every other attribute belongs to the product, the default `level`. The level tells facets and filters that one product may hold several values at once. A release without `attributes.json` derives it: an attribute the catalog writes on variants becomes a variant's.

**Reference:** [`level`](/docs/reference/release-files/attributes#level)

## A filter picks the variant

A tile stands for the whole product, every color included, until the shopper chooses a variant's value. Then it shows the first variant that meets every choice, and names it in `variant`:

```sh title="Terminal"
curl -s http://127.0.0.1:7800/v1/search -H 'Content-Type: application/json' \
  -d '{"on": "category_page", "category": "wohnen/sofas", "filters": {"color": "green"}}' \
  | jq -c '.sections[] | select(.type == "product") | .hits[] | {entity, variant, color: .fields["attributes.color"]}'
```

```json title="Answer: 200 · 4.4 ms · release b25a6aaa"
{"entity":"product:SOFA-ASKA-2","variant":"SOFA-ASKA-2-SALBEI","color":"Salbei"}
{"entity":"product:SOFA-LUND-3","variant":"SOFA-LUND-3-MOSS","color":"Moosgrün"}
```

Sage (Salbei) and moss green (Moosgrün) both belong to the group green. Each tile takes its variant's values, and its title, URL and photos where the variant has its own, so the Aska shows sage. Without a filter, `variant` is left out and the Aska's tile lists both colors.

<Callout type="warn">
    The tile's offer stays the whole product's. Under a grey filter the Aska shows grey, but still at the 649 € sale
    price only sage has; the [product page](/docs/product-pages#variants) has each variant's own offer.
</Callout>

A facet counts tiles, so with one tile per product a sofa counts once, however many of its variants match. Where variants differ, some counts can only be [upper bounds](/docs/reference/glossary#upper-bound), and the answer marks them ([Upper bounds](/docs/facets#upper-bounds)).

**Reference:** [`variant`](/docs/reference/query-api#search.answer.sections.hits.variant)

## A tile per product, variant or color

`listing` in `types.json` says what one tile stands for:

```json title="types.json"
{ "types": [{ "type": "product", "listing": { "axis": "color" } }] }
```

- `"product"`, the default: one tile per product.
- `"variant"`: one tile per variant, with the variant's own offer.
- `{ "axis": "color" }`: one tile per value of an attribute the variants differ by. The bed `BETT-NORA` lists twice: grey, which comes in three sizes, and sage.

A finer tile shows its first variant's title, URL and photos, and a product that does not vary by the axis stays one tile. The axis is one option, quantity or boolean at `level: variant`. Changing `listing` rebuilds the indexes in an [index run](/docs/reference/glossary#index-run).

**Reference:** [`listing`](/docs/reference/release-files/types#listing)

## Next

- [Product pages](/docs/product-pages#variants): each variant with its options and offer.
- [Live prices and stock](/docs/prices-and-stock): change a variant's price between two catalogs.
- [Facets and filters](/docs/facets): the choices that pick a variant.
