App development
Your Shopify Events subscriptions break on your next deploy, not today
September 2026 halved the Events query complexity limit and reshaped fields_changed, trigger syntax and delivery headers. Existing subscriptions keep running until you deploy anything at all. Here is the audit.
Bas Lefeber
Founder, learnshopify.dev · September 29, 2026 · 5 min read
Two changelog entries a week apart in September 2026 changed how Shopify Events work: updates to Events payloads and subscription configuration on the 16th, and the subscription query complexity limit dropping to 100 points on the 22nd. Four separate things changed. None of them broke your app.
That is the problem. Existing subscriptions keep running exactly as they are, and the new rules apply the next time you deploy your shopify.app.toml. So this does not fail on a date Shopify picked. It fails during whatever unrelated change you ship next, which might be a Friday hotfix, and the error will be about your Events config rather than the thing you were actually doing.
The short version
Four changes. The complexity ceiling for a subscription query halved from 250 to 100 points. fields_changed went from a flat array to an object of added / updated / removed. Parent triggers now need an explicit terminal wildcard (product.variants.*). The shopify-event-id and shopify-resource-id delivery headers are gone. Find out where you stand in one command: shopify app deploy --no-release.
Run the cheap check first
Before reading the rest of this, run the command that turns a vague worry into a number. --no-release validates your configuration and creates an app version without releasing it to anyone.
shopify app deploy --no-releaseIf a subscription query exceeds 100 points, this returns a validation error that reports both the calculated value and the maximum allowed. That is a precise, actionable number, produced without touching production, and it is the difference between "we should look at Events at some point" and "this one subscription is at 180 and needs splitting".
Change 1: the complexity ceiling halved
Shopify computes a subscription's complexity from the Admin API fields you select and the connection sizes you request, for the API version configured for Events. Some fields carry custom costs, so counting fields by hand does not give you the total. The ceiling moved from 250 points to 100 on September 22.
The fix is almost never to trim a field here and there until you scrape under the line. It is to notice that an expensive subscription is usually one subscription doing several jobs. Shopify's optimization guide lists four techniques, and they are worth reading in order of how much they typically save:
- Use exact triggers instead of wildcards.
product.titleandproduct.statusinstead ofproduct.*. A wildcard makes you pay for a query broad enough to serve every possible trigger. - Query the changed node directly. When the trigger hands you the child's ID, fetch that node rather than paginating the parent's connection to go find it.
- Delete the connections you were only using to search.
variants(first: 100)is expensive and usually exists because someone needed one variant. - Target metafields by namespace and key. Rather than loading the whole metafield collection and filtering in your handler.
Splitting is allowed, and it is usually the right answer
You can create several subscriptions on the same topic with different queries. A single subscription that handles price changes, inventory changes and title changes is carrying the union of three queries and paying for all of it on every event. Three subscriptions, each with the query its own trigger actually needs, is cheaper, easier to reason about, and easier to change later without re-testing the other two.
Change 2: fields_changed has a new shape
This one requires a code change in your handler, not just config. fields_changed used to be a flat array of names. It is now an object with three arrays.
{ "fields_changed": ["title", "variants", "tags"]}{ "fields_changed": { "added": ["tags"], "updated": ["title"], "removed": ["variants"] }}This is a genuine improvement rather than churn. The old array told you a field was involved; it could not tell you whether a relationship had been attached, changed or detached, so handlers queried the resource again just to find out which. Now that distinction arrives in the payload. A handler that only cares about removals can stop doing a round trip on every event.
The migration hazard is quiet: code that did fields_changed.includes('title') does not throw against an object, it just returns false forever. Grep for every read of fields_changed rather than trusting your tests to catch it, because a handler that silently stops matching is not a test failure, it is a feature that quietly stops firing.
Change 3: parent triggers need a terminal wildcard
A parent trigger must now end in an explicit wildcard. Leaf triggers are untouched.
| Trigger | Status | Note |
|---|---|---|
product.variants | Update it | A parent trigger with no terminal wildcard |
product.variants.* | Correct | The same intent, written explicitly |
product.variants.price | Unchanged | A leaf trigger, always was specific |
Separately, an event subscription using the update action now requires at least one trigger. A subscription that listened to every update on a topic is no longer expressible, which is deliberate: that subscription was almost always both the most expensive one an app had and the one whose handler started with a large conditional.
Change 4: two delivery headers are gone
shopify-event-id and shopify-resource-id are no longer included in event deliveries. Unlike the other three, this one is not waiting for your next deploy. It affects traffic now.
Shopify's guidance is to update your API packages to their latest versions, which handle it. Do that, and then check whether anything of your own read those headers directly. Idempotency keys are the usual culprit: a handler that deduplicated on shopify-event-id is now deduplicating on undefined, which in most implementations means either everything is a duplicate or nothing is. Both are bad in different directions, and neither raises an error.
Learn this properly · free lesson
React to new orders: the orders/create webhook
Build a real subscription handler end to end, including the verification and idempotency that decide whether it survives contact with production. Free to work through from here.
Try this lesson — freeThe audit, in order
- Run
shopify app deploy --no-release. Numbers before opinions. It tells you which subscriptions are over 100 points and by how much. - Grep for
fields_changedin your handlers. Every array method on it is now wrong and none of them will throw. - Grep for
shopify-event-idandshopify-resource-id. Check your idempotency and logging paths first; that is where they live. - Add terminal wildcards to parent triggers and give every
updatesubscription at least one trigger. - Split before you trim. If a subscription is over the ceiling, the question is which jobs it is doing, not which field to sacrifice.
- Bump your Shopify API packages. The header removal is handled for you there, and it is the one change already live.
The professional habit worth taking from this is smaller than the changelog. When a platform says existing configuration keeps working but new rules apply on your next deploy, that is not reassurance, it is a warning with the timing left blank. The right response is to schedule the deploy yourself, on a quiet afternoon, rather than discover the config error in the middle of shipping something else.
Frequently asked questions
What is the new Shopify Events query complexity limit?
100 points, down from 250, effective September 22, 2026. Complexity is computed from the Admin API fields a subscription selects and the connection sizes it requests, for the API version configured for Events, and some fields carry custom costs so counting fields by hand will not give you the total.
How do I check my Events subscription complexity?
Run shopify app deploy --no-release. It validates your configuration and creates an app version without releasing it, and if a subscription exceeds the limit the validation error reports both the calculated value and the maximum allowed. It is safe to run against production config because nothing is released.
Will my existing Shopify Events subscriptions stop working?
Not immediately. Existing subscriptions keep running under the old rules, and the new rules apply the next time you deploy your shopify.app.toml. That makes the failure latent rather than scheduled: it surfaces during whatever unrelated change you ship next, which is why auditing deliberately beats waiting.
What changed about fields_changed in Shopify Events?
It changed from a flat array of field names to an object with added, updated and removed arrays, so a handler can tell whether a resource or relationship was attached, changed or detached without querying again. The migration hazard is that array methods on it now silently return false rather than throwing, so grep for every read of it.
Why do Shopify Events parent triggers need a wildcard now?
A parent trigger must end in an explicit terminal wildcard, so product.variants becomes product.variants.*. Leaf triggers like product.variants.price are unchanged. The change makes broad subscriptions declare that they are broad, which is the same intent behind the lower complexity ceiling. Separately, subscriptions using the update action now need at least one trigger.
What replaces the shopify-event-id and shopify-resource-id headers?
Both were removed from event deliveries, and Shopify's guidance is to update your API packages to their latest versions, which handle the change. Check your own code too: handlers that used shopify-event-id as an idempotency key will now be deduplicating against an undefined value, which fails silently in either direction depending on the implementation.
Start free
Ready to become a Shopify developer?
You just read how it works. Now write it yourself: real tickets from a live store, in an editor where the storefront updates as you type. Module 1 is free, no card.
Free · No credit card · Your first win in minutes
About the author
Bas Lefeber, Founder, learnshopify.dev
Bas builds learnshopify.dev, where developers learn production-grade Shopify theme development against a live storefront. He writes about Liquid, theme architecture, and the parts of the job that still matter now that AI writes the code.
Keep going in the curriculum



