Move metafield access outside loops
Move metafield access outside loops, avoid variant-level metafield checks, limit metaobject loops, and use theme settings instead of metafields when data doesn't change per product.
The most common performance issue with metafields is accessing them inside nested loops. Each metafield access queries the backend, multiplied by variants per product, multiplied by products in collection. For 50 products × 10 variants, that's 500 metafield lookups minimum, which can add seconds to TTFB.
Metaobject loops are particularly expensive: Looping over metaobject entries adds significant overhead, and each entry access queries the backend. An unpaginated loop yields at most 50 entries per page; wrapping it in paginate lets you walk further, which multiplies the backend work rather than removing it. Use metaobject loops only when the page needs them.
The alternative approach is to move metafield access outside loops when possible. For data that doesn't change per product, use theme settings instead of metafields. For complex metafield queries or filtering by metafield values, use the GraphQL Admin API instead of Liquid loops. This is beyond theme scope, but worth knowing for app development.
Anchor to Better pattern: access metafields onceBetter pattern: access metafields once
If a metafield doesn't change between iterations, then read it once before the loop and reuse the variable:
A metafield that changes on each iteration, such as product.metafields.custom.featured, can't be hoisted out of the loop. For those, reduce how many lookups each iteration makes by staying at the product level instead of the variant level.
Anchor to Avoid variant-level metafield loopsAvoid variant-level metafield loops
If you must check variant metafields, then minimize the checks:
Anchor to Limit metaobject loopsLimit metaobject loops
The key after metaobjects is the metaobject definition type, so metaobjects.<type>.values returns the entries for that definition. Use the top-level metaobjects object. The shop.metaobjects form is deprecated.
Anchor to Check metafield existenceCheck metafield existence
Check whether a metafield exists before using it to avoid errors, but minimize these checks in loops:
Anchor to Move to theme settingsMove to theme settings
For data that doesn't change per product, use theme settings instead of metafields:
If you compare a date to a theme setting, then normalize both sides first. There's no date input type for theme settings, so the setting is a string, and comparing it directly to product.created_at raises Liquid error: comparison of ActiveSupport::TimeWithZone with String failed on the storefront:
Anchor to ExamplesExamples
Common antipattern: checking the metafield for every variant.
Both examples keep the variant <select> so that the only difference is where the metafield lookup happens. Don't copy that picker: product.variants returns at most 250 variants, so the picker silently omits options on high-variant products. Build pickers from product.options_with_values instead. Refer to Avoid over-fetching product variants.
Both examples keep the variant <select> so that the only difference is where the metafield lookup happens. Don't copy that picker: product.variants returns at most 250 variants, so the picker silently omits options on high-variant products. Build pickers from product.options_with_values instead. Refer to Avoid over-fetching product variants.
Metaobjects and metafields: Metafields extend existing resources, such as products, variants, and collections. Metaobjects create new custom resources, such as testimonials, FAQs, and ingredients. Both have performance costs when accessed in loops. Use metafields for product-specific data. Use metaobjects sparingly for custom content that needs to be managed separately.
Metaobjects and metafields: Metafields extend existing resources, such as products, variants, and collections. Metaobjects create new custom resources, such as testimonials, FAQs, and ingredients. Both have performance costs when accessed in loops. Use metafields for product-specific data. Use metaobjects sparingly for custom content that needs to be managed separately.
Anchor to TestingTesting
- Theme Inspector: Use the sandwich view to identify repetitive metafield access.
- Compare TTFB: Test before and after removing nested metafield loops.
- Test with realistic data: Use products that have metafields populated to see the real impact.
Anchor to ReferencesReferences
fortagiftagcollection.productscollection.metafieldsproduct.variantsproduct.metafieldsvariant.metafieldsmetafieldobjectproduct.selected_or_first_available_variantmetaobjects- Metafield Liquid object
- Metaobject Liquid object
- Metaobject definition - loop over entries
- Theme Inspector - Complex operations inside loops
- Avoid deeply nested Liquid loops
- Move operations outside loops
- Avoid excessive conditionals in loops