Avoid over-fetching product variants
Load only the variant data you need for initial page render instead of iterating over all product variants, which forces expensive database queries that slow TTFB.
Iterating over product.variants forces the server to load and process all variant data during page rendering. For products with hundreds or thousands of variants (Shopify supports up to 2,048 variants), this significantly increases TTFB by loading unnecessary data.
Most product pages need only option names and values for the option picker, not full variant data for every combination. Loading all variants is wasteful when you need only the selected variant's details.
Anchor to Use ,[object Object], for option pickersUse options_with_values for option pickers
options_with_values for option pickersThe product.options_with_values object provides option data without loading full variant objects. It significantly reduces rendering time while still providing availability information through product_option_value.available and selection state through product_option_value.selected.
Replace variant iteration with product.options_with_values:
Benefits:
- Loads only option data, not all variant data.
- Faster rendering with reduced TTFB.
- Works with products of any variant count.
product_option_value.availableprovides availability without loading variants.product_option_value.selectedsimplifies state management.
Anchor to When variant access is acceptableWhen variant access is acceptable
Checking properties without iteration is fine:
Anchor to Defer variant loading with the Section Rendering APIDefer variant loading with the Section Rendering API
Use JavaScript to fetch updated variant information when a buyer selects an option value. Read the selected option value IDs from the picker's data-option-value-id attributes and pass them as the option_values parameter. You can pass the IDs in any order, and a partial set is fine: options that you leave out fall back to their first available value.
Scope the lookup to the picker that fired the event with event.target.closest(). A document-wide querySelector returns the first match on the page, which is the wrong section when a page renders more than one product:
Anchor to ExamplesExamples
Anchor to Problematic pattern: iterates all variantsProblematic pattern: iterates all variants
This loads and iterates through every variant, dramatically slowing TTFB for high-variant products.
Anchor to Recommended pattern: uses ,[object Object]Recommended pattern: uses options_with_values
options_with_valuesLoads only option data, and works efficiently regardless of variant count.
Anchor to Acceptable variant usageAcceptable variant usage
Anchor to TestingTesting
- Use the Theme Inspector flame graph to check whether variant iteration is slowing TTFB.
- Compare TTFB in the Chrome DevTools Network panel before and after switching to
product.options_with_values. - Test with high-variant products. Create a test product with 100 or more variants to see the impact.
- Check the rendering time difference between products with 10 variants and products with 1,000 variants.
Anchor to ReferencesReferences
product.options_with_valuesproduct_option_valueobjectproduct_option_value.availableproduct_option_value.selectedproduct_option_value.idproduct.variantsproduct.variants_countproduct.selected_or_first_available_variantfortagformtagmoneyfilter- More To Sell, Less To Manage: Introducing 2,048 Product Variants on Shopify
- Support high-variant products
- Defer child product loading in combined listings
- Avoid deeply nested Liquid loops
- Use the Section Rendering API for dynamic updates