Reset inventory levels daily, with Mechanic.

Mechanic is a development and ecommerce automation platform for Shopify. :)

Reset inventory levels daily

This task resets your inventory levels at the default location in your shop, every night, for all products within a given collection.

Runs Occurs every day at midnight (in local time). Configuration includes inventory level to apply and collection.

15-day free trial – unlimited tasks

Developer details

Mechanic is designed to benefit everybody: merchants, customers, developers, agencies, Shopifolks, everybody.

That’s why we make it easy to configure automation without code, why we make it easy to tweak the underlying code once tasks are installed, and why we publish it all here for everyone to learn from.

(By the way, have you seen our documentation? Have you joined the Slack community?)

Open source
View on GitHub to contribute to this task
Subscriptions
mechanic/scheduler/daily
Tasks use subscriptions to sign up for specific kinds of events. Learn more
Options
inventory level to apply (number, required) , collection (picker, collection, required)
Code
{% assign inventory_level_to_apply = options.inventory_level_to_apply__number_required %}
{% assign collection_id = options.collection__picker_collection_required %}

{% assign location_id = shop.primary_location_id | prepend: "gid://shopify/Location/" %}

{% comment %}
  -- get all product IDs from the configured collection
{% endcomment %}

{% assign cursor = nil %}
{% assign product_ids = array %}

{% for n in (1..100) %}
  {% capture query %}
    query {
      collection(id: {{ collection_id | json }}) {
        products(
          first: 250
          after: {{ cursor | json }}
        ) {
          pageInfo {
            hasNextPage
            endCursor
          }
          nodes {
            id
          }
        }
      }
    }
  {% endcapture %}

  {% assign result = query | shopify %}

  {% if event.preview %}
    {% capture result_json %}
      {
        "data": {
          "collection": {
            "products": {
              "nodes": [
                {
                  "id": "gid://shopify/Product/1234567890"
                }
              ]
            }
          }
        }
      }
    {% endcapture %}

    {% assign result = result_json | parse_json %}
  {% endif %}

  {% assign collection = result.data.collection %}
  {% assign product_ids
    = collection.products.nodes
    | map: "id"
    | concat: product_ids
    %}

  {% if result.data.collection.products.pageInfo.hasNextPage %}
    {% assign cursor = result.data.collection.products.pageInfo.endCursor %}
  {% else %}
    {% break %}
  {% endif %}
{% endfor %}

{% comment %}
  -- make sure collection exists and has products
{% endcomment %}

{% if collection == blank %}
  {% log "Collection not found by ID." %}
  {% break %}

{% elsif product_ids == blank %}
  {% log "No products found in the collection." %}
  {% break %}
{% endif %}

{% comment %}
  -- determine which inventory levels need to be set on this task run
{% endcomment %}

{% assign inventory_adjustments = array %}

{% for product_id in product_ids %}
  {% comment %}
    -- get all variants for this product, and their inventory items and inventory levels at the default location
  {% endcomment %}

  {% capture query %}
    query {
      product(id: {{ product_id | json }}) {
        id
        handle
        variants(first: 2048) {
          nodes {
            inventoryItem {
              id
              tracked
              inventoryLevel(locationId: {{ location_id | json }}) {
                quantities(names: "available") {
                  quantity
                }
              }
            }
          }
        }
      }
    }
  {% endcapture %}

  {% assign result = query | shopify %}

  {% if event.preview %}
    {% capture result_json %}
      {
        "data": {
          "product": {
            "variants": {
              "nodes": [
                {
                  "inventoryItem": {
                    "id": "gid://shopify/InventoryItem/1234567890",
                    "tracked": "true",
                    "inventoryLevel": {
                      "quantities": [
                        {
                          "quantity": {{ inventory_level_to_apply | minus: 1 }}
                        }
                      ]
                    }
                  }
                }
              ]
            }
          }
        }
      }
    {% endcapture %}

    {% assign result = result_json | parse_json %}
  {% endif %}

  {% comment %}
    -- if a variant's inventory is tracked (i.e. managed by Shopify) and the available quantity at the default location differs from the configured level, then add it to adjustments array
  {% endcomment %}

  {% for variant in result.data.product.variants.nodes %}
    {% if variant.inventoryItem.tracked and variant.inventoryItem.inventoryLevel.quantities.first.quantity != inventory_level_to_apply %}
      {% assign delta = inventory_level_to_apply | minus: variant.inventoryItem.inventoryLevel.quantities.first.quantity %}

      {% assign inventory_adjustment = hash %}
      {% assign inventory_adjustment["inventoryItemId"] = variant.inventoryItem.id %}
      {% assign inventory_adjustment["locationId"] = location_id %}
      {% assign inventory_adjustment["delta"] = delta %}
      {% assign inventory_adjustment["changeFromQuantity"] = variant.inventoryItem.inventoryLevel.quantities.first.quantity %}
      {% assign inventory_adjustments = inventory_adjustments | push: inventory_adjustment %}
    {% endif %}
  {% endfor %}
{% endfor %}

{% comment %}
  -- changeFromQuantity field is required as of 2026-04
  https://shopify.dev/changelog/making-changefromquantity-field-required
  -- Shopify will enforce idempotency for several mutations as of 2026-04
  https://shopify.dev/changelog/making-idempotency-mandatory-for-inventory-adjustments-and-refund-mutations
{% endcomment %}

{% if inventory_adjustments != blank %}
  {% assign groups_of_inventory_adjustments = inventory_adjustments | in_groups_of: 250, fill_with: false %}

  {% for group_of_inventory_adjustments in groups_of_inventory_adjustments %}
    {% capture idempotent_key %}
      {
        "task_id": {{ task.id | json }},
        "event_id": {{ event.id | json }},
        "data": {{ group_of_inventory_adjustments | json }}
      }
    {% endcapture %}

    {% action "shopify" %}
      mutation {
        inventoryAdjustQuantities(
          input: {
            reason: "correction"
            name: "available"
            changes: {{ group_of_inventory_adjustments | graphql_arguments }}
          }
        ) @idempotent(key: {{ idempotent_key | json | md5 | json }}) {
          inventoryAdjustmentGroup {
            reason
            changes(quantityNames: "available") {
              name
              delta
              item {
                id
                sku
              }
              location {
                name
              }
            }
          }
          userErrors {
            code
            field
            message
          }
        }
      }
    {% endaction %}
  {% endfor %}
{% endif %}
Task code is written in Mechanic Liquid, an extension of open-source Liquid enhanced for automation. Learn more