Retrieve Product Variant's Inventory in Storefront

In this guide, you'll learn how to retrieve a product variant's inventory quantity in a storefront.

How to Retrieve a Product Variant's Inventory Quantity?#

To retrieve variants' inventory quantity using either the List Products or Retrieve Products API routes:

  1. Pass in the fields query parameter the value +variants.inventory_quantity.
    • When also retrieving prices, make sure to include *variants.calculated_price in the beginning of the list of fields. For example, ?fields=*variants.calculated_price,+variants.inventory_quantity.
  2. Pass the publishable API key in the header of the request, which you always do when sending a request to the Store API. The inventory quantity is retrieved based on the stock locations of the sales channels that belong to the API key's scope.
    • If you're using the JS SDK, the publishable API key is automatically passed in the header of the requests as explained in the Publishable API Keys guide.

For example:

Important: If you're also passing *variants.calculated_price in fields to get the product variants' prices, make sure to include it in the beginning of the list of fields. For example, ?fields=*variants.calculated_price,+variants.inventory_quantity.
Code
1sdk.store.product.retrieve(id, {2  fields: `*variants.calculated_price,+variants.inventory_quantity`,3})4.then(({ product }) => {5  product.variants?.forEach((variant) => {6    const isInStock = variant.manage_inventory === false || 7      variant.inventory_quantity > 08
9    // ...10  })11})

In this example, you retrieve the product variants' inventory quantity by passing +variants.inventory_quantity in the fields query parameter. This will add a new inventory_quantity field to each variant object.

When is a Variant in Stock?#

A variant is in stock if:

  1. Its manage_inventory's value is false, meaning that Medusa doesn't keep track of its inventory.
  2. If its inventory_quantity's value is greater than 0.
    • This property is only available on variants whose manage_inventory is false.
    • If the variant doesn't have inventory levels in the stock location associated with the API's scope, its inventory_quantity will be null.

Full React Example#

For example, to show on a product's page whether a variant is in stock in a React-based storefront:

Tip: Learn how to install and configure the JS SDK in the JS SDK documentation.
React Storefront
1"use client" // include with Next.js 13+2
3import { useEffect, useMemo, useState } from "react"4import { HttpTypes } from "@medusajs/types"5import { sdk } from "@/lib/sdk"6
7type Props = {8  id: string9}10
11export default function Product({ id }: Props) {12  const [loading, setLoading] = useState(true)13  const [product, setProduct] = useState<14    HttpTypes.StoreProduct | undefined15  >()16  const [selectedOptions, setSelectedOptions] = useState<Record<string, string>>({})17
18  useEffect(() => {19    if (!loading) {20      return 21    }22
23    sdk.store.product.retrieve(id, {24      fields: `*variants.calculated_price,+variants.inventory_quantity`,25    })26    .then(({ product: dataProduct }) => {27      setProduct(dataProduct)28      setLoading(false)29    })30  }, [loading])31
32  const selectedVariant = useMemo(() => {33    if (34      !product?.variants ||35      !product.options || 36      Object.keys(selectedOptions).length !== product.options?.length37    ) {38      return39    }40
41    return product.variants.find((variant) => variant.options?.every(42      (optionValue) => optionValue.value === selectedOptions[optionValue.option_id!]43    ))44  }, [selectedOptions, product])45
46  const isInStock = useMemo(() => {47    if (!selectedVariant) {48      return undefined49    }50
51    return selectedVariant.manage_inventory === false || 52      (selectedVariant.inventory_quantity || 0) > 053  }, [selectedVariant])54
55  return (56    <div>57      {loading && <span>Loading...</span>}58      {product && (59        <>60          <h1>{product.title}</h1>61          {(product.options?.length || 0) > 0 && (62            <ul>63              {product.options!.map((option) => (64                <li key={option.id}>65                  {option.title}66                  {option.values?.map((optionValue) => (67                    <button 68                      key={optionValue.id}69                      onClick={() => {70                        setSelectedOptions((prev) => {71                          return {72                            ...prev,73                            [option.id!]: optionValue.value!,74                          }75                        })76                      }}77                    >78                      {optionValue.value}79                    </button>80                  ))}81                </li>82              ))}83            </ul>84          )}85          {selectedVariant && (86            <span>Selected Variant: {selectedVariant.id}</span>87          )}88          {isInStock !== undefined && (89            <span>90              {isInStock && "In Stock"}91              {!isInStock && "Out of Stock"}92            </span>93          )}94        </>95      )}96    </div>97  )98}

In this example, you retrieve the product variants' inventory quantity by passing +variants.inventory_quantity in the fields query parameter. This will add a new inventory_quantity field to each variant object.

Then, you find the selected variant and show whether it's in stock. The variant is in stock if its manage_inventory property is disabled, or the inventory_quantity is greater than 0.

Tip: Refer to the Select Product Variants guide to learn more about selecting a product variant.
Was this page helpful?
Ask Anything
Ask any questions about Medusa. Get help with your development.
You can also use the Medusa MCP server in Cursor, VSCode, etc...
FAQ
What is Medusa?
How can I create a module?
How can I create a data model?
How do I create a workflow?
How can I extend a data model in the Product Module?
Recipes
How do I build a marketplace with Medusa?
How do I build digital products with Medusa?
How do I build subscription-based purchases with Medusa?
What other recipes are available in the Medusa documentation?
Chat is cleared on refresh
Line break