Shopify GraphQL API: 4 Admin vs Storefront Decisions Before Production

Engineer reviewing API setup on laptop

Use the GraphQL Admin API reference when you are building apps or backend integrations that manage products, orders, and store data, and use the GraphQL Storefront API when you are building customer-facing storefronts or headless commerce experiences. Both run on GraphQL with official client libraries and interactive tooling, so your choice comes down to whether you need merchant-level scopes or public catalog access.


TL;DR:

  • Public apps use OAuth with scopes merchants approve, while custom integrations can use private tokens created in a single store; keep Admin credentials out of browser code.
  • Pin each integration to an explicit quarterly API version and schedule upgrades; monitor query costs, since deeply nested fields consume more of Shopify’s refillable limit.
  • For exports above a few thousand records, use bulk operations; ordinary queries should follow cursors and stop when hasNextPage is false.
  • Public Storefront tokens can read public data only, while private tokens can enable customer account changes and must stay on the server.
  • Check userErrors after Admin mutations because HTTP 200 does not guarantee success; test changes on a development store before modifying production data.

Quicktoimpress
quicktoimpress.com
Build a Shopify system ready to scale
Quicktoimpress combines senior strategy with hands-on Shopify engineering to build and improve commerce systems around your priorities.
Explore Shopify engineering

Table of Contents

Admin API vs Storefront API: how the two surfaces divide the work

The Admin GraphQL API handles everything a merchant or an app needs to manage a store: products, inventory, orders, customers, fulfillment, and metafields. If you are building an app that appears in the Shopify App Store, syncs inventory with a warehouse system, or automates order processing, this is the surface you query.

Admin and Storefront API responsibilities separated

The Storefront API, by contrast, is built for what shoppers see and do: browsing a catalog, building a cart, applying discount codes, and checking out. It is deliberately scoped down so a public-facing token cannot touch sensitive merchant data. According to Shopify’s own documentation, the Storefront API is available only through GraphQL, which means any headless storefront project needs to commit to GraphQL patterns from day one rather than treating them as optional.

The scope difference is the real driver behind which API you pick:

  • Admin API tokens carry granular permissions tied to an app’s installed scopes, covering sensitive operations like refunds or customer data exports.
  • Storefront API tokens are intentionally limited to public catalog and cart operations, safe to expose in client-side code.
  • Admin API calls typically originate from a server or app backend; Storefront API calls often run directly from a browser or edge function.
  • Choosing wrong early, such as trying to manage inventory through the Storefront API, means a rebuild later rather than a quick fix.

Most production projects end up using both: the Admin API for internal tooling and the Storefront API for the customer experience layer, often inside a framework like Hydrogen.

How authentication works across tokens and scopes

Getting authentication right the first time saves you from a painful migration later. Shopify splits access into a few distinct patterns depending on what you are building and who is calling the API.

  1. Public apps use OAuth: your app redirects a merchant through Shopify’s authorization flow, receives an access token tied to the scopes the merchant approved, and stores that token for subsequent Admin API requests.
  2. Custom and private integrations use server-to-server tokens: generated directly in the Shopify admin for a single store, these tokens skip the OAuth dance but should never be exposed outside your backend.
  3. Storefront API supports both public and private tokens: a public Storefront access token is safe for client-side use and limited to read operations on public data, while a private Storefront token (used server-side) can unlock additional capabilities like customer account mutations.
  4. Token refresh and rotation: Admin API access tokens for public apps do not expire on a fixed schedule, but you should still build rotation into your credential handling so a compromised token has a short useful life.

A typical authenticated request using the Fetch API looks like a POST to the GraphQL endpoint with an X-Shopify-Access-Token header and a JSON body containing your query and variables. For the Storefront API, the header is X-Shopify-Storefront-Access-Token instead.

Pro Tip: Keep Admin API tokens out of any code that ships to a browser, and store them in a secrets manager rather than environment files committed to version control.

Official tools and client libraries worth knowing

Shopify maintains a small, well-defined toolset rather than leaving developers to roll their own GraphQL clients from scratch. Picking the right tool up front shortens your build time considerably.

  • The Shopify GraphiQL App gives you an interactive browser-based interface to explore the schema and test queries against a real store before writing any integration code.
  • The @shopify/shopify-api npm package covers Node.js app development, handling OAuth, session storage, and typed GraphQL requests in one library.
  • A dedicated Ruby gem exists for server-side Ruby applications that need the same session and request handling.
  • React Router packages published alongside the Node SDK support embedded app development without hand-rolling auth middleware.
  • Raw cURL requests work fine for quick one-off testing, since the GraphQL endpoint accepts standard HTTP POST requests with no SDK required.

For headless storefronts specifically, Shopify Hydrogen wraps the Storefront API client in a React framework built for commerce, handling cart state, SEO, and routing conventions out of the box. We cover the practical tradeoffs of adopting Hydrogen, including where storefronts tend to break on upgrades, in our piece on avoiding quarterly storefront breaks.

Endpoints, API versions, and request shape

The Admin GraphQL endpoint follows a predictable pattern: https://{shop}.myshopify.com/admin/api/{version}/graphql.json, where {version} is a quarterly release like 2025-10. The Storefront API endpoint follows a similar structure but lives under /api/{version}/graphql.json and expects the Storefront token header instead of the Admin one.

Shopify ships a new API version every quarter and supports each version for a defined window before retiring it, so pin your integration to an explicit version string rather than leaving it unset. Partner guidance on API versioning strategy, including sunset planning and telemetry for tracking deprecated fields, applies directly here: treat version upgrades as a scheduled maintenance task, not a surprise.

Every request, regardless of SDK, boils down to a JSON payload with a query string and an optional variables object, sent as a POST with Content-Type: application/json and the appropriate access token header.

Writing efficient queries: connections, cursors, and pagination

Shopify’s schema leans heavily on the GraphQL connection pattern, where any list of resources, products, orders, collections, comes back as a set of edges, each wrapping a node plus a cursor. This is standard GraphQL behavior as defined by the GraphQL specification itself, and Shopify applies it consistently across the entire schema.

  1. Use first and after together to page forward through results, passing the last cursor from your previous response as the after value on the next request.
  2. Request only the fields you need on each node, since nested connections multiply query cost quickly when you ask for variants, images, and metafields all at once.
  3. Reuse fragments across queries that share the same shape, such as a ProductCard fragment used in both a collection listing and a search results query.
  4. Switch to bulk operations for large exports, like syncing an entire product catalog, instead of paginating through thousands of pages of a standard query.

Bulk operations run asynchronously on Shopify’s infrastructure and notify you via webhook when the export file is ready, which is dramatically more efficient than looping through cursor pages for anything beyond a few thousand records.

Pro Tip: Build your pagination loop to stop based on hasNextPage rather than a fixed page count, since catalog size changes over time and a hardcoded limit will silently drop data.

Staying within rate limits and keeping queries fast

Shopify’s GraphQL APIs use cost-based throttling rather than simple request counts. Every query is assigned a calculated cost based on the fields and connections it touches, and each store has a bucket of available cost that refills over time. A query requesting deeply nested connections can consume far more of that bucket than a flat, narrow query, even if both return in a single request.

A few habits keep you comfortably inside your limit:

  • Request only the fields your UI or integration actually renders, dropping unused metafields and nested connections.
  • Avoid nesting more than two or three levels deep in a single query; split deeply related data into a second request if needed.
  • Paginate aggressively with smaller page sizes rather than requesting hundreds of items at once.
  • Read the extensions.cost object Shopify returns with every response to track actual cost against your limit in real time.

For production apps, build retry logic with exponential backoff for THROTTLED errors, and add a health check that periodically confirms your token is still valid and your query cost stays within a safe margin of the bucket size.

Sample queries and mutations you can adapt

A basic Admin API query for product data with variants looks like a products connection request, pulling title, handle, and a nested variants connection with price and inventoryQuantity. Keep the variant selection narrow unless you genuinely need every field, since variants are where query cost adds up fastest.

  • An Admin query fetching product metadata should request only the metafields your integration reads, identified by namespace and key, rather than pulling every metafield on the product.
  • A Storefront query for a product listing page typically requests handle, title, featuredImage, and a priceRange, scoped to a collection via its handle.
  • Cart creation on the Storefront side uses the cartCreate mutation, passing line items as input and reading back the returned cart.id for subsequent cartLinesAdd calls.
  • A product update mutation on the Admin side, like productUpdate, returns a userErrors array that you should check on every response, since GraphQL can return a 200 status even when the mutation logically failed.

Testing mutations against a development store before touching production data catches most userErrors issues early, particularly around required fields and invalid ID formats.

How we approach production-grade Shopify GraphQL integrations

Shopify and commerce platform engineering sits inside our growth platforms work, where we build and maintain the systems that sit behind a storefront rather than treating an integration as a one-time project.

A production integration checklist we hold every build to: pin an explicit API version and track its sunset date, store credentials in a secrets manager with rotation built in, monitor query cost against the throttling bucket, handle userErrors on every mutation, and version-control your GraphQL fragments alongside your application code. We bring in a growth engineering partner when a team has outgrown prototype-level scripts and needs a system that survives version upgrades and traffic spikes without a rebuild.

What the documentation does not tell you about shipping this in production

Shopify’s official docs are thorough on schema and syntax, but thin on the operational discipline that separates a working prototype from an integration that survives a Black Friday traffic spike or a quarterly API version deprecation. The conventional advice treats versioning and rate limits as edge cases to handle later. In practice, they are the two things that quietly break more integrations than any query syntax mistake.

The reader should prioritize two things before writing a single query: a plan for pinning and upgrading API versions on a schedule, and a monitoring habit around query cost rather than waiting for a THROTTLED error in production to notice a problem. Most teams get the GraphQL syntax right on the first try. Far fewer build the operational scaffolding, version tracking, credential rotation, cost monitoring, that keeps the integration healthy a year later. That scaffolding, not the query language itself, is where production reliability actually comes from.

— Service

Get help building your Shopify GraphQL integration

Building a Shopify integration that holds up past the prototype stage takes more than correct query syntax: it takes version tracking, credential handling, and monitoring built in from the start. We can embed directly with client teams to design and ship systems from Admin API backend work to Storefront and headless builds, aiming to provide one accountable partner rather than a handoff between strategy and execution.

Quicktoimpress

If your team is ready to move a Shopify GraphQL integration from prototype to production, check our engagement options and tell us what you are building.

FAQ

What is the difference between Shopify’s Admin and Storefront GraphQL APIs?

The Admin GraphQL API manages merchant-facing data like products, orders, and inventory, while the Storefront API serves customer-facing catalog, cart, and checkout data. Pick the Admin API for backend or app-level work and the Storefront API for anything a shopper interacts with directly.

Do I need to use GraphQL instead of Shopify’s REST API?

Shopify’s own communications describe a strategic shift toward GraphQL as the primary way to build on the platform, and the Storefront API is available only in GraphQL. REST remains usable for some Admin API tasks, but new storefront and many admin features are GraphQL-first.

How does Shopify’s GraphQL rate limiting work?

Shopify uses cost-based throttling, where each query is assigned a calculated cost and every store has a cost bucket that refills over time rather than a simple per-minute request count. Narrower queries with fewer nested fields consume less of that bucket, which keeps you further from a THROTTLED response.

How do I handle pagination in Shopify’s GraphQL API?

Shopify’s list fields follow the standard GraphQL connection pattern defined by GraphQL.org, returning edges, node data, and a cursor you pass as the after argument on the next request. Check hasNextPage on the pageInfo object to know when to stop paginating instead of relying on a fixed count.

Which tools should I use to test Shopify GraphQL queries?

The Shopify GraphiQL App gives you an interactive interface for testing queries against a real store before writing integration code. For scripted testing, official SDKs like @shopify/shopify-api on npm or direct cURL requests both work against the same GraphQL endpoint.

Sources