How to Use GraphQL API in Magento 2 for Headless Commerce
Magento 2 provides a GraphQL API that enables headless commerce architectures. GraphQL allows frontend applications to request exactly the data they need in a single request, making it the preferred API for PWA storefronts and custom frontends. Understanding how GraphQL behaves differently from the traditional Magento frontend helps avoid unexpected issues.
GraphQL Endpoint
The GraphQL endpoint is available at:
https://your-store.com/graphql
For multi-store setups, include the store code in the header:
Store: store_view_code
Common Queries
Product Search
{
products(search: "jacket", pageSize: 10, currentPage: 1) {
total_count
items {
sku
name
price_range {
minimum_price {
regular_price {
value
currency
}
}
}
small_image {
url
label
}
}
}
}
Category Listing
{
categoryList(filters: { ids: { eq: "42" } }) {
id
name
product_count
children {
id
name
url_path
}
}
}
Cart Operations
mutation {
addProductsToCart(
cartId: "cart-id-here"
cartItems: [
{
quantity: 1
sku: "product-sku"
}
]
) {
cart {
items {
id
product {
name
sku
}
quantity
}
}
}
}
Authentication
Guest Operations
Cart creation, product browsing, and category listing work without authentication. Create a guest cart:
mutation {
createEmptyCart
}
Customer Operations
For customer-specific operations (viewing orders, managing account, accessing wish lists), include a customer token in the Authorization header:
mutation {
generateCustomerToken(email: "[email protected]", password: "password") {
token
}
}
Then include the token in subsequent requests:
Authorization: Bearer <customer-token>
Tokens have a configurable expiration time set in Stores → Configuration → Services → OAuth → Access Token Expiration.
Sorting Behavior: GraphQL vs Frontend
Magento uses different backends for GraphQL and the traditional (Luma/Hyva) frontend:
- Frontend catalog queries: MySQL-based queries
- GraphQL product queries: Elasticsearch/OpenSearch-based queries
This means sorting results can differ between the two channels when multiple products have the same relevance score or position value. For example, products with identical position values in a category may appear in different orders via GraphQL compared to the frontend.
This is expected behavior, not a bug. The two engines use different tiebreaker logic for equal-score results.
Solution: If consistent ordering across both channels is important, use explicit secondary sort criteria in GraphQL queries:
{
products(
filter: { category_id: { eq: "42" } }
sort: { position: ASC, entity_id: ASC }
pageSize: 20
) {
items {
sku
name
}
}
}
Adding entity_id (or another unique field) as a secondary sort ensures deterministic ordering regardless of the backend engine.
Schema Introspection
Explore the available queries and mutations using introspection:
{
__schema {
queryType {
fields {
name
description
}
}
mutationType {
fields {
name
description
}
}
}
}
Tools like GraphQL Playground, Altair, or Insomnia provide visual interfaces for exploring the schema and testing queries.
Performance Considerations
- Request only needed fields: GraphQL's advantage is requesting only the data you need. Avoid requesting all available fields on product queries.
- Use pagination: Always include
pageSizeandcurrentPageparameters. Requesting entire catalogs in a single query overwhelms the server. - Cache GraphQL responses: Magento supports HTTP caching for GET-based GraphQL queries. Configure Varnish or CDN caching for frequently requested queries.