- Get Started
- Product
- Resources
- Tools & SDKs
- Framework
- Reference
- Get Started
- Product
- Resources
- Tools & SDKs
- Framework
- Reference
Inventory Kits
In this guide, you'll learn how inventory kits can be used in the Medusa application to support use cases like multi-part products, bundled products, and shared inventory across products.
What is an Inventory Kit?#
An inventory kit is a collection of inventory items that are linked to a single product variant. These inventory items can be used to represent different parts of a product, or to represent a bundle of products.
The Medusa application links inventory items from the Inventory Module to product variants in the Product Module. Each variant can have multiple inventory items, and these inventory items can be re-used or shared across variants.
Using inventory kits, you can implement use cases like:
- Multi-part products: A product that consists of multiple parts, each with its own inventory item.
- Bundled products: A product that is sold as a bundle, where each variant in the bundle product can re-use the inventory items of another product that should be sold as part of the bundle.
Multi-Part Products#
Consider your store sells bicycles that consist of a frame, wheels, and seats, and you want to manage the inventory of these parts separately.
To implement this in Medusa, you can:
- Create inventory items for each of the different parts.
- For each bicycle product, add a variant whose inventory kit consists of the inventory items of each of the parts.
Then, whenever a customer purchases a bicycle, the inventory of each part is updated accordingly. You can also use the required_quantity
of the variant's inventory items to set how much quantity is consumed of the part's inventory when a bicycle is sold. For example, the bicycle's wheels require 2 wheels inventory items to be sold when a bicycle is sold.
Create Multi-Part Product#
Using the Medusa Admin, you can create a multi-part product by creating its inventory items first, then assigning these inventory items to the product's variant(s).
Using workflows, you can implement this by first creating the inventory items:
1import { 2 createInventoryItemsWorkflow, 3 useQueryGraphStep4} from "@medusajs/medusa/core-flows"5import { createWorkflow } from "@medusajs/framework/workflows-sdk"6 7export const createMultiPartProductsWorkflow = createWorkflow(8 "create-multi-part-products",9 () => {10 // Alternatively, you can create a stock location11 const { data: stockLocations } = useQueryGraphStep({12 entity: "stock_location",13 fields: ["*"],14 filters: {15 name: "European Warehouse"16 }17 })18 19 const inventoryItems = createInventoryItemsWorkflow.runAsStep({20 input: {21 items: [22 {23 sku: "FRAME",24 title: "Frame",25 location_levels: [26 {27 stocked_quantity: 100,28 location_id: stockLocations[0].id29 }30 ]31 },32 {33 sku: "WHEEL",34 title: "Wheel",35 location_levels: [36 {37 stocked_quantity: 100,38 location_id: stockLocations[0].id39 }40 ]41 },42 {43 sku: "SEAT",44 title: "Seat",45 location_levels: [46 {47 stocked_quantity: 100,48 location_id: stockLocations[0].id49 }50 ]51 }52 ]53 }54 })55 56 // TODO create the product57 }58)
You start by retrieving the stock location to create the inventory items in. Alternatively, you can create a stock location.
Then, you create the inventory items that the product variant consists of.
Next, create the product and pass the inventory item's IDs to the product's variant:
1import { 2 // ...3 transform4} from "@medusajs/framework/workflows-sdk"5import { 6 // ...7 createProductsWorkflow8} from "@medusajs/medusa/core-flows"9 10export const createMultiPartProductsWorkflow = createWorkflow(11 "create-multi-part-products",12 () => {13 // ...14 15 const inventoryItemIds = transform({16 inventoryItems17 }, (data) => {18 return data.inventoryItems.map((inventoryItem) => {19 return {20 inventory_item_id: inventoryItem.id,21 // can also specify required_quantity22 }23 })24 })25 26 const products = createProductsWorkflow.runAsStep({27 input: {28 products: [29 {30 title: "Bicycle",31 variants: [32 {33 title: "Bicycle - Small",34 prices: [35 {36 amount: 100,37 currency_code: "usd"38 }39 ],40 options: {41 "Default Option": "Default Variant"42 },43 inventory_items: inventoryItemIds44 }45 ],46 options: [47 {48 title: "Default Option",49 values: ["Default Variant"]50 }51 ]52 }53 ]54 }55 })56 }57)
You prepare the inventory item IDs to pass to the variant using transform from the Workflows SDK, then pass these IDs to the created product's variant.
You can now execute the workflow in API routes, scheduled jobs, or subscribers.
Bundled Products#
Consider you have three products: shirt, pants, and shoes. You sell those products separately, but you also want to offer them as a bundle.
You can do that by creating a product, where each variant re-uses the inventory items of each of the shirt, pants, and shoes products.
Then, when the bundled product's variant is purchased, the inventory quantity of the associated inventory items are updated.
Create Bundled Product#
You can create a bundled product in the Medusa Admin by creating the products part of the bundle first, each having its own inventory items. Then, you create the bundled product whose variant(s) have inventory kits composed of inventory items from each of the products part of the bundle.
Using workflows, you can implement this by first creating the products part of the bundle:
1import { 2 createWorkflow,3} from "@medusajs/framework/workflows-sdk"4import { 5 createProductsWorkflow,6} from "@medusajs/medusa/core-flows"7 8export const createBundledProducts = createWorkflow(9 "create-bundled-products",10 () => {11 const products = createProductsWorkflow.runAsStep({12 input: {13 products: [14 {15 title: "Shirt",16 variants: [17 {18 title: "Shirt",19 prices: [20 {21 amount: 10,22 currency_code: "usd"23 }24 ],25 options: {26 "Default Option": "Default Variant"27 },28 manage_inventory: true29 }30 ],31 options: [32 {33 title: "Default Option",34 values: ["Default Variant"]35 }36 ]37 },38 {39 title: "Pants",40 variants: [41 {42 title: "Pants",43 prices: [44 {45 amount: 10,46 currency_code: "usd"47 }48 ],49 options: {50 "Default Option": "Default Variant"51 },52 manage_inventory: true53 }54 ],55 options: [56 {57 title: "Default Option",58 values: ["Default Variant"]59 }60 ]61 },62 {63 title: "Shoes",64 variants: [65 {66 title: "Shoes",67 prices: [68 {69 amount: 10,70 currency_code: "usd"71 }72 ],73 options: {74 "Default Option": "Default Variant"75 },76 manage_inventory: true77 }78 ],79 options: [80 {81 title: "Default Option",82 values: ["Default Variant"]83 }84 ]85 }86 ]87 }88 })89 90 // TODO re-retrieve with inventory91 }92)
You create three products and enable manage_inventory
for their variants, which will create a default inventory item. You can also create the inventory item first for more control over the quantity as explained in the previous section.
Next, retrieve the products again but with variant information:
1import { 2 // ...3 transform4} from "@medusajs/framework/workflows-sdk"5import { 6 useQueryGraphStep7} from "@medusajs/medusa/core-flows"8 9export const createBundledProducts = createWorkflow(10 "create-bundled-products",11 () => {12 // ...13 const productIds = transform({14 products15 }, (data) => data.products.map((product) => product.id))16 17 // @ts-ignore18 const { data: productsWithInventory } = useQueryGraphStep({19 entity: "product",20 fields: [21 "variants.*",22 "variants.inventory_items.*"23 ],24 filters: {25 id: productIds26 }27 })28 29 const inventoryItemIds = transform({30 productsWithInventory31 }, (data) => {32 return data.productsWithInventory.map((product) => {33 return {34 inventory_item_id: product.variants[0].inventory_items?.[0]?.inventory_item_id35 }36 })37 })38 39 // create bundled product40 }41)
Using Query, you retrieve the product again with the inventory items of each variant. Then, you prepare the inventory items to pass to the bundled product's variant.
Finally, create the bundled product:
1export const createBundledProducts = createWorkflow(2 "create-bundled-products",3 () => {4 // ...5 const bundledProduct = createProductsWorkflow.runAsStep({6 input: {7 products: [8 {9 title: "Bundled Clothes",10 variants: [11 {12 title: "Bundle",13 prices: [14 {15 amount: 30,16 currency_code: "usd"17 }18 ],19 options: {20 "Default Option": "Default Variant"21 },22 inventory_items: inventoryItemIds,23 }24 ],25 options: [26 {27 title: "Default Option",28 values: ["Default Variant"]29 }30 ]31 }32 ]33 }34 }).config({ name: "create-bundled-product" })35 }36)
The bundled product has the same inventory items as those of the products part of the bundle.
You can now execute the workflow in API routes, scheduled jobs, or subscribers.