Dead stock and slow-moving inventory analysis
This report identifies variants that are active and in stock but have not been sold within a selected period — or have never been sold. The goal is to surface slow-moving and dead stock so that action can be taken: markdowns, clearance, bundling, or purchasing reviews to free up warehouse space and recover tied-up capital.
It is most useful during monthly or quarterly inventory reviews, or whenever stock turnover and warehouse capacity are being evaluated.
This article covers analysis at the variant level. For analysis at the product or SKU level, see Variations and extensions below.
⚠️ Dead stock and aging inventory analyses typically use the most recent date an item was received into inventory. As Shopify does not expose this data to external apps, the date of last sale is used as a proxy. Results should be treated accordingly — a variant with no recent sales may still have been restocked recently.
In this article
- How the report works
- Steps to build the report
- Interpreting the results
- Variations and extensions
- Need more support?
How the report works
The report is built on the Variants primary table, where each row represents a single variant. This is the correct table for this analysis because it includes all variants regardless of whether they have sold, making it possible to surface variants with no recent sales activity alongside their current inventory levels and variant-level data such as price and cost. The report starts from the built-in Inventory by variant report, which already includes the key dimensions and measures needed: Product title, Variant title, and Total inventory quantity.
One custom field is required:
- Days since last sold: Returns the number of days that have passed since a variant was last sold by comparing the date returned by the built-in Last sold at dimension to the current date. If a variant has never been sold, the field returns a null value.
This field returns no value for variants that have never been sold — these variants are captured by a separate OR filter condition rather than the days threshold.
The report is filtered to show active, in-stock variants where Days since last sold ≥ 180 or Days since last sold is in [Unknown] . The 180-day threshold can be adjusted to match your sales cycle or inventory review process.
Steps to build the report
💡 Prefer to skip the setup? If you'd like this report built for you, contact our team through the Help widget in the bottom-right corner. We typically respond within one business day.
Step 1 — Open the Inventory by variant report
- Open the Reports tab
- Open the Inventory by variant report in the Variants reports section
Step 2 — Create the Days since last sold custom field
This custom dimension calculates the number of days between the built-in Last sold at dimension and the current date. It updates automatically each time the report is run.
- Select Edit, then + Create new, then Create Dimension
- Confirm the Table is set to Variant
- Set the Display name to Days since last sold
- Set the Description to Calculates the number of days since the variant last sold
- Set the Data type to Number and Numeric type to Number
- Enter the following calculation:
DATEDIFF(DAY, [$.LastSoldAt], TODAY())
- Select Save
Step 3 — Add fields to the report
Add the following fields to the report.
| Field | Type |
|---|---|
| Last sold at | Dimension |
| Days since last sold | Dimension (custom) |
Step 4 — Add filters
This report requires both AND and OR filter logic. See Filter a report for guidance on combining filter conditions.
To restrict the report to active, in-stock variants:
- Select Add filter, choose Status from the Products table, and select
activefrom the value list - Select Add filter, choose Inventory quantity, set the operator to greater than, and enter
0
To restrict the report to variants with no sales in the last 180 days or variants that have never sold:
- Select Add filter, choose Days since last sold, set the operator to greater than or equal, and enter
180 - Hover over the Days since last sold filter and select + OR
- Choose Days since last sold again and select
[Unknown]from the value list
The OR condition is needed because variants that have never been sold have no value in Days since last sold and would not be captured by the ≥ 180 filter alone.
Step 5 — Sort the report
Adjust the sort order to suit your needs. Sorting by Days since last sold descending shows the variant that has not sold for the longest period first. Sorting ascending shows variants that have never sold first, followed by those most recently sold.
Step 6 — Save the report
Select Save as and save a copy of the report with a name such as Variants with no sales in the last 180 days.
Interpreting the results
Each row represents an active variant that is currently in stock and has either not been sold in the last 180 days or has never been sold. Note that the report cannot show whether a variant was active and in stock for the entire period, or when the most recent restock occurred — a variant with no recent sales may have been replenished recently.
Useful patterns to look for:
- Days since last sold is unknown — the variant has never sold. Review whether the item is newly launched or carrying inventory that has never generated demand. To investigate further, add the Created at date to the report to see when the variant was first created.
- Very high days since last sold — the variant has been dormant for an extended period. Consider discounting, bundling, transferring stock, or removing the variant from active sale if demand is unlikely to return.
- Variants with substantial inventory quantity — these represent stock tying up the most capital and warehouse space. Prioritise these variants when planning inventory reduction or clearance activity.
- Multiple variants of the same product appearing in the report — this can indicate that specific sizes, colours, or configurations are underperforming while other variants of the same product continue to sell. Review whether the product assortment should be simplified.
- Recently crossed the 180-day threshold — variants with values just above 180 may warrant monitoring rather than immediate action, particularly if they are seasonal or have irregular purchasing patterns.
💡 The report uses a default threshold of 180 days. Adjust the Days since last sold filter to match your sales cycle, product lifecycle, or inventory review process.
Variations and extensions
Show the worst variants per product type or vendor
Add Product Type or Vendor as a dimension and adjust the sort hierarchy to group by that field first, followed by the Days since last sold field descending. This shows the most dormant variants within each segment — useful for identifying which product types or vendors have the most slow-moving inventory.
Variants that have never been sold will appear last within each group under this sort order, since they have no value in Days since last sold. To show these variants first within each group, sort Days since last sold ascending instead.
Analyse by product instead of variant
The base report identifies individual variants that have not sold recently. If you want to identify products where no variants have sold in the last 180 days, you can build a product-level version of the report.
Repeat Step 1, except start from the built-in Inventory by product report.
Custom product-level versions of the Last sold at and Days since last sold are required to use the most recent sale date across all variants under a product. Create new dimensions on the Products primary table using the data type Number and numeric type Number, with the following display name and calculations.
| Custom field display name | Approach | Calculation |
|---|---|---|
| Product last sold at | A joined field reference subquery to return the most recent sale date from the Agreement lines table for each product id | (SELECT MAX([i.Date]) FROM [$.AgreementLines i] WHERE [i.Kind] = 'Sale') |
| Product days since last sold | Refer to the BRQL name of the Product last sold at field | DATEDIFF(DAY, [$.ProductLastSoldAt], TODAY()) |
To filter for products that still have stock, a new custom dimension is needed to aggregate inventory across all variants belonging to a product, since inventory lives at the variant level. Create a new dimension on the Products primary table with the display name Inventory quantity, the data type Number and numeric type Number, and the following calculation:
( SELECT SUMZ([v.InventoryQuantity]) FROM [$.Variants v] )
Repeat Steps 3, 4, 5, and 6 using the equivalent product-level fields.
⚠️ Do not modify the existing Variants-based report to build this version — build a new report instead.
Analyse by SKU instead of variant
To group results by SKU rather than individual variant — useful when multiple variants share a SKU and should be treated as a single unit.
To analyse using by SKU, build a new report using Variants as the primary table. Repeat Step 1, except start from the built-in Inventory by SKU report.
A custom version of the built-in Last sold at dimension and Days since last sold custom field created in Step 2 are required to use the most recent sale date across all variants under a product SKU.
| New custom field display name | Approach | Example calculation |
|---|---|---|
| Product SKU last sold date | A direct table subquery joining on product title and SKU rather than variant ID |
|
| Product SKU days since last sold | References the BRQL name of the Product SKU last sold date field | DATEDIFF(DAY, [$.ProductSKULastSoldDate], TODAY()) |
A new inventory quantity field is also needed to sum stock across all variants sharing a product title and SKU, for use in the in-stock filter. Create a new dimension on the Variants primary table with the display name Product SKU inventory quantity, the description Aggregates inventory to the product SKU level, the data type Number and numeric type Number, and the following calculation:
SUMZ([v.InventoryQuantity]) OVER (PARTITION BY [$.Product.Title],[$.SKU])
Repeat Steps 3, 4, 5, and 6 using the equivalent product SKU fields.
💡 The same approach can be applied at other grouping levels — for example, by variant option such as size or colour — by adjusting the fields used in the partition.
Need more support?
If you get stuck or have additional questions, you can contact our team directly through the Help widget in the bottom-right corner — we typically respond within one business day.