Themes have historically used the Liquid API to load all of a product's variants when rendering a product. However, as variant counts increase, this pattern results in a decline in performance. This is especially critical for products with [more than 250 variants](/docs/api/developer-previews#increased-variants-developer-preview) and [combined listings](https://help.shopify.com/manual/products/combined-listings).
To prevent poor render performance in themes, we've restricted [`product.variants`](/docs/api/liquid/objects/product#product-variants) to return a maximum of 250 variants and [added APIs](#new-apis) to solve common use cases that previously required loading all variants. To prepare for increased variant limits, audit your theme for any code that might rely on all product variants to be present.
This guide helps you support high-variant products in your theme by outlining new APIs, identifying code patterns that might not scale with increased variant limits, and providing a walkthrough for how to construct an option value picker.
## New APIs
We've added two APIs to support building themes for high-variant products: a [`product_option_value` object](#product_option_value-object) and [granular option value selection for product URLs](#granular-option-value-selection-for-product-urls).
### `product_option_value` object
The [`product_option_value`](/docs/api/liquid/objects/product_option_value) object provides rich contextual information about each option value based on the active variant selection.
Field |
Application |
available
|
Whether the option value has any available variants, in the context of the selected values for previous options. Enables themes to display a "top-down" availability UX, where an option value is available if any part of its subtree is purchasable.
|
id
|
Option value IDs should be used with granular option value selection when re-rendering the option values section.
|
variant
|
The variant that's associated with this option value, combined with the other currently selected option values (if one exists). In addition to providing trivial access to the variant for the option value, might also simplify option value availability through the variant's available field.
|
selected
|
Whether the option value is selected. May be used instead of a product_option.selected_value == option_value check.
|
product_url
|
The URL of the product associated with this option value. Used by combined listing products to indicate that selecting the option value should load another product’s content.
|
### Granular option value selection for product URLs
The key change to support more variants is to defer loading variant information until it's needed. To facilitate this, we now support a `option_values` parameter on product page URLs. In combination with the [`product_option_value`](/docs/api/liquid/objects/product_option_value) Liquid object, clients can load only the variants that are relevant to the selected option value state.
> Caution:
> If the option combination has no associated variant, then both [`product.selected_or_first_available_variant`](/docs/api/liquid/objects/product#product-selected_or_first_available_variant) and [`product.selected_variant`](/docs/api/liquid/objects/product#product-selected_variant) return `null`.
## Spotting Problematic Code Patterns
Any Liquid code that requires a complete set of product variants won't work as expected if the product contains more than 250 variants. For example, while the the following Liquid code intends to iterate through all variants for the product to render a hidden variant input in the product form, it actually only iterates through the first 250 variants:
> Note:
> Not all variant-related code needs to change. For example, `product.variants.first` or `product.variants.size > 1` will still work because they don't rely on the full variant set.
### How to update your theme
To support high-variant products, we recommend you audit your theme for usage of product [`variants`](/docs/api/liquid/objects/product#product-variants) and `product | json`. Look for opportunities to eliminate overfetching or defer loading variant information until needed, using the [new APIs](#new-apis), [Storefront API](/docs/api/storefront/latest/queries/product), or [Ajax API](/docs/api/ajax/reference/product).
> Note:
> Themes are no longer required to support users that have disabled JavaScript. You can remove any code to handle this.
If these solutions don't work for your use case, then please share your feedback in the [Shopify Developer Community Forum](https://community.shopify.dev).
## Building an option value picker for high-variant products
The most common pattern that requires loading all variants is rendering an option value picker. The key areas that this guide covers are
- [Rendering option values](#rendering-option-values)
- [Loading option value availability](#option-value-availability)
- [Supporting combined listings](#optional-supporting-combined-listings).
You can also refer to Dawn's [product variant picker (https://github.com/Shopify/dawn/blob/main/snippets/product-variant-picker.liquid) for an example implementation.
### Rendering option values
Themes should use [`product.options_with_values`](/docs/api/liquid/objects/product#product-options_with_values) for rendering options, and the new [`product_option_value`](/docs/api/liquid/objects/product_option_value) object returned by [`product_option.values`](/docs/api/liquid/objects/product_option#product_option-values) for option values.
> Tip:
> Refer to [Getting started with swatches for Shopify themes](https://www.shopify.com/partners/blog/swatches) to add support swatches in your option value picker.
### Option value availability
Instead of iterating over all product variants, you can determine option value availability using [`product_option_value.available`](/docs/api/liquid/objects/product_option_value#product_option_value-available) or [`variant.available`](/docs/api/liquid/objects/variant#variant-available).
Using [`product_option_value.available`](/docs/api/liquid/objects/product_option_value#product_option_value-available) results in a "top-down" UX where option values are treated as a tree, and an option value is available if any part of the subtree is purchasable.
Using [`variant.available`](/docs/api/liquid/objects/variant#variant-available) results in an "adjacent" UX where option values are treated as graph nodes, and an option value is available if the node is purchasable.
When a buyer selects an option value, use the [`product_option_value.id`](/docs/api/liquid/objects/product_option_value#product_option_value-id) to make a request to the [Section Rendering API](/docs/api/ajax/section-rendering) to load and display the next option value availability state.
Building on the previous example, the following code sets option value availability and refreshes the section with the new availability state when an option value is selected:
### (Optional) Supporting combined listings
To support [combined listings](https://help.shopify.com/manual/products/combined-listings), themes should load and replace product information when switching between sibling products. You can do this with the [`product_option_value.product_url`](/docs/api/liquid/objects/product_option_value#product_option_value-product_url) property.
For example, a shop has a combined listing `Pants` with child products `Pants - red` and `Pants - green`. When a buyer lands on `Pants` and changes the color, then the UI should update to display information from the corresponding child product, such as price, images, and description.
### Example option value picker
Putting it all together, a theme can load a minimal set of variants using the [`product_option_value.variant`](/docs/api/liquid/objects/product_option_value#product_option_value-variant) object, use the [Section Rendering API](/docs/api/ajax/section-rendering) to load the next availability state by passing the new option value selection, and [support combined listings](#optional-supporting-combined-listings) by replacing product content when a buyer switches to a sibling product: