What is Magento GraphQL ?
Magento GraphQL is the headless API endpoint introduced in Magento 2.3 (Nov 2018) at POST /graphql, exposing the catalog, customer, cart, checkout and order data via GraphQL queries and mutations. Built for PWA Studio, Hyvä-headless, custom React/Vue SPAs, mobile apps and BFF (backend-for-frontend) patterns. One round-trip, client-specified field selection, schema-introspectable.
Five things Magento GraphQL actually does under the hood
GraphQL is not magic — it is a strongly-typed schema, a resolver layer over Magento's service contracts, and HTTP cache integration via Varnish. Here is what that means concretely.
-
01
Single endpoint, client-specified field selection
Magento exposes one URL —
POST /graphql— that accepts every query and mutation. The client sends a query body declaring exactly which fields it wants (name,price,image.url, nestedvariants { sku }) and Magento returns only those fields. There is no field over-fetching the way REST endpoints return entire entity payloads, and no field under-fetching that forces follow-up requests — one round-trip pulls the precise tree the storefront needs. -
02
Schema declared per-module via schema.graphqls files
Each Magento module ships an
etc/schema.graphqlsfile written in GraphQL SDL (Schema Definition Language). The coreMagento_CatalogGraphQlmodule definesproducts,categories,categoryqueries;Magento_QuoteGraphQldefinescart,addProductsToCartmutations;Magento_CustomerGraphQldefinescustomer,createCustomer. Custom modules extend the schema by declaring new types and resolvers in their ownschema.graphqls. The aggregated schema is compiled atsetup:di:compiletime. -
03
Resolvers map GraphQL types to PHP service contracts
Behind every GraphQL field is a Resolver class implementing
Magento\Framework\GraphQl\Query\ResolverInterface. Resolvers re-use the same service contracts (Repository interfaces, Search APIs) the REST layer uses — they are a thin transport adapter, not a parallel data layer. This means GraphQL and REST stay in sync as the catalog, customer, and cart logic evolve. Custom resolvers register against schema fields viaetc/graphql/di.xmlusing theresolverargument. -
04
Cacheable queries cached via Varnish + x-magento-vary
Read queries (catalog browsing, category listing, product detail) are HTTP-cacheable when the resolver returns a
CacheableInterfaceresult with cache tags. Magento setsX-Magento-Cache-IdandX-Magento-Varyheaders; Varnish (or Fastly on Adobe Commerce Cloud) keys the cache on those headers and serves repeat queries from edge memory in under 5 ms. Customer-specific data (cart, customer, wishlist) is uncacheable and falls through to PHP every time. -
05
Mutations bypass cache and run synchronously
Mutations —
addProductsToCart,placeOrder,createCustomer,updateCustomerAddress— bypass HTTP cache by design and execute synchronously through the same service contracts the REST API uses. Each mutation runs inside a Magento DB transaction; failure rolls back state. The response shape mirrors the input mutation, so the client can update its local state from the mutation result without a follow-up read query.
Four situations where GraphQL is the right Magento API
GraphQL is not universally correct — REST is still better for batch / admin work. These four scenarios are unambiguous GraphQL wins.
-
Building PWA Studio, Hyvä-headless or custom SPA
If the storefront is a separate frontend application — PWA Studio (React + Apollo), Hyvä-headless (Hyvä theme talking to Magento purely via GraphQL), Vue Storefront, or a bespoke React/Next.js / Vue/Nuxt SPA — GraphQL is the supported transport. The Adobe-recommended PWA Studio talks GraphQL by default, and every Magento 2.3+ release ships GraphQL coverage for new features the moment they land. Building a headless storefront on REST in 2026 is fighting the platform.
-
Multi-channel app from a single Magento backend
When one Magento instance has to feed a web storefront plus an iOS app plus an Android app plus a kiosk — or any combination — GraphQL lets each client pull only the fields it needs in one request. The mobile app fetches small thumbnails and short descriptions, the web app fetches full image sets and rich HTML, the kiosk fetches inventory + price only. Same backend, same schema, four optimised payloads. REST forces every channel to consume the same fixed entity shape.
-
Deep nested data in one round-trip (kills N+1)
A typical product detail page needs the product, its 8 image variants, its 3 configurable child SKUs, its category breadcrumb, its 12 reviews and the related-products carousel. On REST that is 5 to 7 sequential calls; on a 200 ms RTT mobile network that is over a second of waterfall latency. One GraphQL query pulls the entire nested tree in a single request — everything resolved server-side, returned as one JSON document. Lighthouse-critical Time to First Byte metrics improve by 30 to 60% on data-heavy pages.
-
Avoid for: bulk imports, simple admin tasks
GraphQL is request-per-item by design — great for storefront reads, terrible for batch operations. Importing 10,000 products one mutation at a time will take hours and saturate PHP-FPM. Use the Magento Admin REST API or the bulk async REST endpoints for ingestion, or write directly to the database via
InstallData/DataPatchInterfacefor one-time loads. Keep GraphQL for what it is built for: customer-facing storefront reads and individual cart / checkout / order mutations.
Four traps that turn a GraphQL build into a performance disaster
Every slow Magento headless storefront I have audited makes one or more of these four mistakes. Avoid them and the API runs at edge speed.
-
Querying entire schemas instead of needed fields
A common starter mistake is requesting
products(filter: {...}) { items { ... }}with the autogenerated fullProductInterfacefield set. That pulls every attribute Magento knows about each product — description, short_description, meta_keyword, swatch images, every custom attribute — and a 24-product PLP can return 800 KB of JSON. Specify only the fields the UI actually renders (name, sku, price_range, small_image { url }) and the same query drops below 30 KB. GraphQL's killer feature is field selection — use it. -
Not declaring cache tags on cacheable queries
Custom resolvers default to uncacheable, which means every storefront hit runs the resolver from scratch — no Varnish, no edge cache, full PHP execution per request. Implement
IdentityInterfaceon the resolver result and return cache tags (cat_p_,cat_c_) so Varnish can key and invalidate the response. Addcache: { tags: [...], cacheable: true }declarations inetc/graphql/di.xml. Done correctly, custom storefront queries hit at 50 to 200x lower latency. -
Using GraphQL for bulk imports / batch operations
GraphQL mutations are one-at-a-time by design. Looping
addProductsToCart500 times to seed test orders, orcreateProduct10,000 times to import a CSV catalog, will burn hours of PHP-FPM time, blow pastmax_execution_timedefaults, and likely 502 the gateway. For batch workloads use the Magento Bulk Async REST API (POST /async/bulk/V1/products), direct DB seed via DataPatch, or the Magento_ImportExport CSV pipeline. GraphQL is not the right tool for batch. -
Forgetting Authorization header for customer queries
The
customer,customerCart,customerOrdersqueries are customer-scoped and require anAuthorization: Bearer <token>header. Without it Magento returns a "The current customer isn't authorized" error rather than the customer's data. Issue tokens via thegenerateCustomerTokenmutation, store them client-side (HttpOnly cookie or secure local storage), and send them on every customer-scoped request. Anonymous queries (products,category,cart(cart_id)with a guest mask ID) need no auth header.
Magento GraphQL — frequently asked questions
-
GraphQL vs REST in Magento — which should I use?
Use GraphQL for customer-facing storefront work where the client controls the field selection: PWA Studio, Hyvä-headless, custom SPA, mobile apps. Use REST for admin / backend tasks: bulk imports, ERP integrations, third-party connectors, batch operations, anything that runs as a scheduled job. GraphQL's strengths (single round-trip, field selection, schema introspection) are storefront strengths; its weaknesses (one-mutation-per-call, no native batching, request payload overhead) are batch weaknesses. Most production Magento stores run both side by side. -
Magento GraphQL performance — is it fast?
Cacheable queries (catalog browse, category, product detail with no customer context) hit Varnish / Fastly and respond in 5 to 50 ms at the edge — comparable to REST or faster, since one GraphQL query replaces 5 to 7 REST round-trips on a typical product page. Uncacheable queries (cart, customer, checkout) execute per-request through PHP-FPM at 100 to 400 ms depending on database size and resolver complexity, similar to REST. The biggest perf wins come from killing the N+1 round-trip pattern that REST forces on storefront UIs, not from raw query speed. Always measure on your own data and your own infra. -
Which Magento versions support GraphQL?
GraphQL was introduced in Magento 2.3 (November 2018) and has shipped with every Magento Open Source and Adobe Commerce release since. Coverage has expanded steadily — early versions only supported catalog reads, while 2.4.x covers catalog, cart, checkout, customer, orders, wishlist, B2B (company accounts, requisition lists, negotiable quotes), Page Builder content, and Inventory (MSI). Magento 2.4.6 and later have feature parity with REST for storefront use cases. Magento 2.4.9 (current latest) is the recommended floor for production headless work; older versions may need custom resolvers to fill gaps. -
Can I add custom GraphQL schemas?
Yes — extending the GraphQL schema is a first-class pattern. Createetc/schema.graphqlsin your custom module declaring new types, queries, or mutations in GraphQL SDL syntax. Implement a Resolver class that implementsResolverInterface. Wire the resolver to the schema field viaetc/graphql/di.xml. The aggregated schema is compiled atbin/magento setup:di:compiletime, so re-run that after schema changes. For cacheable resolvers, also implementIdentityInterfaceand return cache tags so Varnish / Fastly can key responses correctly. -
How does authorization work for customer-specific queries?
Customer-scoped queries (customer,customerCart,customerOrders,customerDownloadableProducts) require a customer access token sent in theAuthorization: Bearer <token>HTTP header. Tokens are issued by thegenerateCustomerToken(email, password)mutation and have a configurable lifetime (default 1 hour, set in Stores > Configuration > Services > OAuth). Anonymous storefront queries (products,category,cart(cart_id)using a guest mask ID) need no token. Admin-only queries are not exposed via /graphql at all — admin access stays on /rest with an admin token. -
Are GraphQL queries cached?
Read queries are cacheable when the resolver opts in. The resolver result must implementIdentityInterfaceand return cache tags (cat_p_123for product 123,cat_c_45for category 45). Magento setsX-Magento-Cache-IdandX-Magento-Varyresponse headers; Varnish or Fastly then keys the cache on those headers and serves repeat queries from edge memory. When a tagged entity changes, Magento purges the cache by tag automatically. Mutations are uncacheable by definition. Customer-scoped queries and queries with a logged-in session are also uncacheable — they execute per-request through PHP-FPM every time.
Planning a Magento headless / GraphQL build?
Send your storefront URL or wireframes — I will run a GraphQL coverage check, sketch the resolver / cache architecture, and reply with a written quote, fixed-price scope and earliest start date. 24-business-hour turnaround.