Skip to main content

On This Page

How Shopify's GraphQL Rate Limits Actually Work: Stop Getting 429'd by Budgeting Query Cost

3 min read
Share

These articles are AI-generated summaries. Please check the original sources for full details.

The core idea: cost, not count

Shopify’s GraphQL Admin API limits queries by calculated cost, not request count—a shift from REST that catches many developers off guard. Standard plan buckets hold just 1,000 points and restore at only 50 points per second.

Why This Matters

Treating Shopify’s GraphQL API like REST leads to inevitable 429 errors because the system deducts points based on query complexity, not call frequency. This cost-based model forces developers to budget reads and writes as a finite resource or face throttling that can stall production syncs across millions of operations.

Key Insights

  • —fact: Standard plan (Basic/Shopify/Advanced) caps bucket at 1,000 points with a restore rate of 50 pts/sec; Shopify Plus doubles both to 2,000 pts and 100 pts/sec (source: Muhammad Masad Ashraf, dev.to, June 2026).
  • —concept: Query cost scoring is deterministic—scalar/enum fields cost 0 points, objects cost 1 point per relation, connections cost 2 +1 per item returned, and mutations cost a flat 10 points due to side effects like DB writes and webhooks.
  • —tool: The Bulk Operations API handles datasets over 1,000 records asynchronously with no max query cost or per-query rate limit; ideal for deeply nested connections or bulk exports without touching the token bucket.
  • —fact: Single queries are capped at a maximum of requestedQueryCost: 1000 across all plan tiers; Shopify Plus provides a deeper bucket but cannot run larger individual queries (source: official Shopify documentation referenced in article).
  • —concept: Token-bucket throttling is scoped per app+store pair; one app’s traffic never competes with another app’s budget on the same store—but concurrent workers sharing an app must coordinate via centralized state (e.g., Redis) to avoid race conditions.
  • —tool: The extensions.cost.throttleStatus object in every response exposes maximumAvailable, currentlyAvailable, and restoreRate values—enabling client-side pre-flight checks before dispatching the next query

Working Examples

Practical Applications

  • —use_case: Local token-bucket guard for single-worker apps – implement a TypeScript function that checks estimated query cost against server-reported currentlyAvailable and sleeps dynamically before dispatching. Pitfall: Multiple workers each maintain local estimates without coordination → random ‘429’ spikes when they independently overshoot the shared bucket.
  • —use_case: Exponential backoff with jitter for retries – use algorithm base=2^attempt*100 + Math.random()*100 ms up to max attempts. Pitfall: Naive fixed-interval retries cause stampede failures across concurrent workers when store restores capacity slowly.
  • —use_case: Migrate large dataset reads (>1k records) from synchronous paginated queries to Bulk Operations API – submit async job that returns file without consuming live bucket points. Pitfall: Using synchronous pagination for deeply nested connections wastes budget on repeated round trips that could be handled in one bulk pass.
  • —use_case: Prefer webhooks over polling for change detection – subscribe to relevant events (e.g., product updates) instead of polling regularly. Pitfall Polling burns expensive mutation-level costs on unchanged data — scales poorly into millions of stores/hours

References:

Continue reading

Next article

Feeling Behind in Tech: The Impostor Syndrome of Unseen Progress

Related Content