Using Magento GraphQL for a Headless Product Catalog
Learn how to use Magento’s built‑in GraphQL endpoint (v2.3.5+) to fetch product data for a headless storefront, with a concrete curl example and practical verification steps.
09 Aug 2026, 22:20 UTC

Overview of Magento GraphQL support
Magento Open Source and Commerce have shipped a GraphQL endpoint since version 2.3.5. The endpoint lives at /graphql relative to the store root and exposes the same data that the traditional PHP‑rendered storefront uses, but through a strongly typed schema. This lets a headless front‑end (React, Vue, Svelte, or a mobile app) request exactly the fields it needs while Magento continues to handle cart, checkout, customer, and admin operations in the backend.
Setting up authentication and basic query structure
Before any query can be executed, the client must send a valid HTTP header that identifies the request. Magento supports two common approaches:
- Admin token – obtain a token via the
/rest/V1/integration/admin/tokenREST endpoint using an admin username and password. This token works for all GraphQL queries that require admin privileges (e.g., managing categories). - Customer token – obtain a token via the
/rest/V1/integration/customer/tokenendpoint with a customer’s email and password. This token is scoped to that customer and is suitable for cart, wishlist, and order queries.
Both tokens are JWT‑style strings; they are placed in the Authorization: Bearer <token> header. No additional configuration is required if the default routes are enabled, which they are in a standard Magento 2.3.5+ installation.
A minimal GraphQL request looks like this:
curl -X POST "https://example.com/graphql" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..." \
-d '{"query":"{ products(pageSize: 2) { items { sku name } } }"}'
The response is JSON with a data object matching the shape of the query.
Worked example: fetching a product list with filters and pagination
Suppose we want to display the first 10 products from category ID 3, showing SKU, name, price, and stock status. The following query uses the products resolver with a filter on category ID and pageSize for pagination.
curl -X POST "https://example.com/graphql" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..." \
-d '{
"query": "\n query ProductsInCategory($catId: Int!, $pageSize: Int!) {\n products(filter: {category_id: {eq: $catId}}, pageSize: $pageSize) {\n total_count\n items {\n sku\n name\n price {\n regularAmount {\n value\n currency\n }\n }\n stock_status\n }\n }\n }\n ",
"variables": {
"catId": 3,
"pageSize": 10
}
}'
If the request succeeds, the JSON body will contain:
{
"data": {
"products": {
"total_count": 57,
"items": [
{
"sku": "24-MB01",
"name": "Joust Duffle Bag",
"price": {
"regularAmount": {
"value": 34,
"currency": "USD"
}
},
"stock_status": true
},
... // up to 9 more items
]
}
}
}
To verify that the endpoint is working, you can run an introspection query that asks for the schema’s root type:
curl -X POST "https://example.com/graphql" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..." \
-d '{"query":"{ __schema { queryType { name } } }"}'
A successful response returns JSON with "queryType":{"name":"RootQuery"}. If you receive an HTML error page or a 404, check that Magento’s web server rewrites are enabled and that the /graphql route is not blocked by a firewall or a custom env.php setting.
Trade‑offs: learning curve, caching, and version compatibility
While GraphQL gives fine‑grained data fetching, it introduces a few operational considerations:
- Learning curve – Front‑end teams must become comfortable with the GraphQL language, especially when dealing with nested objects like product price tiers or tiered discounts. Magento’s schema is documented in the developer docs, but the depth can be intimidating at first.
- Caching – Unlike traditional full‑page caching, GraphQL responses vary by query variables, making generic HTTP caching less effective. A common pattern is to cache the results of frequent queries (e.g., category product lists) in Redis or Varnish using a hash of the query string and variables as the cache key.
- Version compatibility – The GraphQL schema evolves with each Magento release. Custom modules that add attributes or entities must declare their GraphQL types via
schema.graphqlsfiles. If you pin your store to a specific Magento version (e.g., 2.4.5‑p1), test any custom schema upgrades in a staging environment before promoting to production.
Actionable steps
- Confirm your Magento version: run
composer show magento/product-community-edition(or the enterprise equivalent) and ensure the version is ≥2.3.5. - Test endpoint accessibility with the introspection query shown above; look for a JSON response containing the schema’s query type.
- Generate an admin or customer token via the REST
/tokenendpoints and store it securely (e.g., in an environment variable or a secret manager). - Implement the sample product‑list query in your front‑end code, handling pagination with the
total_countfield and updating UI as the user scrolls or changes page size. - Monitor response times; if average latency exceeds your budget, consider adding a reverse‑proxy cache layer keyed on the query string and variables, and enable Magento’s built‑in full‑page cache for anonymous users.
By following these steps you can expose Magento’s catalog data through a modern, efficient API while retaining the platform’s robust admin and checkout capabilities.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.