Product Bundles in Shopify (No Apps Required)

How to Create Product Bundles in Shopify Using Variant Metafields (No Apps Required)

Table of Contents

  1. Why use metafields for bundles?
  2. Step 1: Add a metafield definition
  3. Step 2: Add bundle components to variants
  4. Step 3: Liquid logic to check availability
  5. Step 4: Show or disable the add-to-cart button
  6. Conclusion

Why use metafields for bundles?

Shopify doesn’t support real bundles natively, and apps can be slow, bloated, or expensive. With a bit of Liquid and metafields, you can create virtual bundles that reuse existing SKUs, track real inventory, and update dynamically depending on selected variant.

Step 1: Add a metafield definition

Go to Settings → Metafields and metaobjects in your Shopify Admin. Then:

  1. Click Variants
  2. Click Add definition
  3. Call it something like “Bundle Components”
  4. Set Namespace and key to: custom.bundle_components
  5. Choose Single line text as the content type
  6. Click Save

Step 2: Add bundle components to variants

Now go to any product you want to use as a bundle. For each variant (e.g. Size M, Size L), scroll down to the Metafields section.

Insert a comma-separated list of SKUs that make up this bundle variant. For example:

SKU123, SKU456, SKU789

Each of these must correspond to existing variant SKUs in your store (that are actively stocked).

Step 3: Liquid logic to check availability

Paste this near the top of your product template:

{% raw %}
{% liquid
  assign variant_available = current_variant.available
  assign bundle_skus = current_variant.metafields.custom.bundle_components | split: ','
  assign is_bundle = false
  assign is_bundle_available = true

  if bundle_skus.size > 0 and bundle_skus.first != blank
    assign is_bundle = true

    for sku in bundle_skus
      assign trimmed_sku = sku | strip
      assign found_variant = nil

      for p in collections.all.products
        for v in p.variants
          if v.sku == trimmed_sku
            assign found_variant = v
          endif
        endfor
      endfor

      if found_variant == nil or found_variant.available == false
        assign is_bundle_available = false
      endif
    endfor
  endif
%}
{% endraw %}

This block checks if the variant is a bundle, and whether all its components are in stock.

Step 4: Show or disable the add-to-cart button

Now, update your button text logic (and disable state) like this:

{% raw %}

  {% if variant_available and is_bundle_available %}
    {{ button_text }}
  {% else %}
    sold out
  {% endif %}

{% endraw %}

You can also update Alpine.js or Vue bindings with similar logic if you’re using a JS framework.

Conclusion

This approach gives you full control over Shopify bundles:

  • No paid apps
  • Faster page load (no injected JS)
  • Real inventory sync — since you’re using real SKUs
  • Variant-specific bundles for sizes, colours, kits, and more

Need help implementing this on your theme? I work with Shopify stores running custom themes like Label and Dawn — and can help you build performant, flexible bundle logic with zero bloat.