Retrieve Product Variant's Inventory in Storefront

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

  1. Pass the publishable API key in the header of the request. The retrieved inventory quantity is in the locations associated with the key's sales channels.
  2. Pass in the fields query parameter the value +variants.inventory_quantity.

For example:

Code
1const queryParams = new URLSearchParams({2  fields: `*variants.calculated_price,+variants.inventory_quantity`,3})4
5fetch(`http://localhost:9000/store/products/${id}?${queryParams.toString()}`, {6  credentials: "include",7  headers: {8    "x-publishable-api-key": process.env.NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY || "temp",9  },10})11.then((res) => res.json())12.then(({ product }) => {13  product.variants?.forEach((variant) => {14    const isInStock = variant.manage_inventory === false || 15      variant.inventory_quantity > 016
17    // ...18  })19})
ImportantIf 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.

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.

Full React Example#

React Storefront
1"use client" // include with Next.js 13+2
3import { useEffect, useMemo, useState } from "react"4import { HttpTypes } from "@medusajs/types"5
6type Props = {7  id: string8}9
10export default function Product({ id }: Props) {11  const [loading, setLoading] = useState(true)12  const [product, setProduct] = useState<13    HttpTypes.StoreProduct | undefined14  >()15  const [selectedOptions, setSelectedOptions] = useState<Record<string, string>>({})16
17  useEffect(() => {18    if (!loading) {19      return 20    }21
22    const queryParams = new URLSearchParams({23      fields: `+variants.inventory_quantity`,24    })25
26    fetch(`http://localhost:9000/store/products/${id}?${queryParams.toString()}`, {27      credentials: "include",28      headers: {29        "x-publishable-api-key": process.env.NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY || "temp",30      },31    })32    .then((res) => res.json())33    .then(({ product: dataProduct }) => {34      setProduct(dataProduct)35      setLoading(false)36    })37  }, [loading])38
39  const selectedVariant = useMemo(() => {40    if (41      !product?.variants ||42      !product.options || 43      Object.keys(selectedOptions).length !== product.options?.length44    ) {45      return46    }47
48    return product.variants.find((variant) => variant.options?.every(49      (optionValue) => optionValue.value === selectedOptions[optionValue.option_id!]50    ))51  }, [selectedOptions, product])52
53  const isInStock = useMemo(() => {54    if (!selectedVariant) {55      return undefined56    }57
58    return selectedVariant.manage_inventory === false || selectedVariant.inventory_quantity > 059  }, [selectedVariant])60
61  return (62    <div>63      {loading && <span>Loading...</span>}64      {product && (65        <>66          <h1>{product.title}</h1>67          {(product.options?.length || 0) > 0 && (68            <ul>69              {product.options!.map((option) => (70                <li key={option.id}>71                  {option.title}72                  {option.values?.map((optionValue) => (73                    <button 74                      key={optionValue.id}75                      onClick={() => {76                        setSelectedOptions((prev) => {77                          return {78                            ...prev,79                            [option.id!]: optionValue.value!,80                          }81                        })82                      }}83                    >84                      {optionValue.value}85                    </button>86                  ))}87                </li>88              ))}89            </ul>90          )}91          {selectedVariant && (92            <span>Selected Variant: {selectedVariant.id}</span>93          )}94          {isInStock !== undefined && (95            <span>96              {isInStock && "In Stock"}97              {!isInStock && "Out of Stock"}98            </span>99          )}100        </>101      )}102    </div>103  )104}

In this example, you show whether the selected variant is in or out of stock.

Was this page helpful?
Edit this page
Ask Anything
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