Mechanic is a development and ecommerce automation platform for Shopify. :)
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.
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?)
mechanic/scheduler/daily
{% 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 %}