Skip to main content
Back to Articles
MagentoSeptember 15, 20258 min read

Magento 2 GraphQL API for Mobile Applications

Build performant mobile commerce experiences using Magento 2 GraphQL API with optimized queries, caching strategies, and offline-first architecture.

GraphQL for Mobile Commerce

Mobile commerce demands fast, efficient API calls over potentially slow cellular connections. REST APIs return fixed data structures, often sending more data than the client needs or requiring multiple round-trips to assemble a single screen. GraphQL solves both problems by letting the client specify exactly which fields to fetch in a single request.

Magento 2 ships with a comprehensive GraphQL API covering catalog, cart, checkout, customer accounts, and CMS content. This guide covers how to build performant mobile applications against this API, with optimization patterns proven in Magento 2 production environments.

Optimized Query Patterns

Product Listing Page

Mobile screens display less data than desktop. Fetch only what the UI renders:

query CategoryProducts($id: String!, $page: Int!, $size: Int!) {
  products(
    filter: { category_uid: { eq: $id } }
    pageSize: $size
    currentPage: $page
    sort: { position: ASC }
  ) {
    total_count
    items {
      uid
      sku
      name
      url_key
      price_range {
        minimum_price {
          final_price { value currency }
          discount { percent_off }
        }
      }
      small_image {
        url
        label
      }
      review_count
      rating_summary
    }
    page_info {
      current_page
      total_pages
    }
  }
}

This query returns approximately 200 bytes per product versus 2-3KB from the equivalent REST endpoint. For a 20-product listing page, that is a 90 percent reduction in payload size.

Product Detail Page

query ProductDetail($urlKey: String!) {
  products(filter: { url_key: { eq: $urlKey } }) {
    items {
      uid
      sku
      name
      description { html }
      short_description { html }
      price_range {
        minimum_price {
          regular_price { value currency }
          final_price { value currency }
          discount { amount_off percent_off }
        }
      }
      media_gallery {
        url
        label
        position
        ... on ProductVideo {
          video_content { video_url video_title }
        }
      }
      ... on ConfigurableProduct {
        configurable_options {
          attribute_uid
          label
          values {
            uid
            label
            swatch_data {
              value
              ... on ImageSwatchData { thumbnail }
              ... on ColorSwatchData { value }
            }
          }
        }
        variants {
          attributes {
            uid
            label
            code
          }
          product {
            uid
            sku
            price_range {
              minimum_price {
                final_price { value currency }
              }
            }
            stock_status
          }
        }
      }
      related_products {
        uid
        name
        url_key
        small_image { url }
        price_range {
          minimum_price {
            final_price { value currency }
          }
        }
      }
    }
  }
}

Use GraphQL fragments to share field selections across queries and reduce duplication in your mobile codebase.

Cart Operations

Efficient Cart Management

mutation AddToCart($cartId: String!, $sku: String!, $qty: Float!) {
  addProductsToCart(
    cartId: $cartId
    cartItems: [{ sku: $sku, quantity: $qty }]
  ) {
    cart {
      id
      total_quantity
      prices {
        grand_total { value currency }
        subtotal_excluding_tax { value currency }
        applied_taxes { label amount { value } }
        discounts { label amount { value } }
      }
      items {
        uid
        quantity
        product {
          name
          sku
          small_image { url }
        }
        prices {
          row_total { value currency }
          total_item_discount { value }
        }
      }
    }
  }
}

Return the full cart state after every mutation. This eliminates the need for a separate cart fetch, saving a round-trip on every cart interaction.

Authentication Flow

Customer Token Management

mutation CustomerLogin($email: String!, $password: String!) {
  generateCustomerToken(email: $email, password: $password) {
    token
  }
}
// Mobile client token management
class AuthManager {
  private token: string | null = null;
  private refreshTimer: NodeJS.Timeout | null = null;

  async login(email: string, password: string): Promise<void> {
    const { data } = await this.client.mutate({
      mutation: LOGIN_MUTATION,
      variables: { email, password },
    });

    this.token = data.generateCustomerToken.token;
    await SecureStore.setItemAsync("auth_token", this.token);

    // Magento tokens expire after 1 hour by default
    this.refreshTimer = setInterval(() => this.refreshToken(), 50 * 60 * 1000);
  }

  getHeaders(): Record<string, string> {
    return this.token ? { Authorization: `Bearer ${this.token}` } : {};
  }
}

Caching Strategy for Mobile

Apollo Client Configuration

import { ApolloClient, InMemoryCache } from "@apollo/client";
import { persistCache, AsyncStorageWrapper } from "apollo3-cache-persist";
import AsyncStorage from "@react-native-async-storage/async-storage";

const cache = new InMemoryCache({
  typePolicies: {
    Query: {
      fields: {
        products: {
          keyArgs: ["filter", "sort"],
          merge(existing, incoming, { args }) {
            if (args?.currentPage === 1) return incoming;
            return {
              ...incoming,
              items: [...(existing?.items || []), ...incoming.items],
            };
          },
        },
      },
    },
    SimpleProduct: { keyFields: ["uid"] },
    ConfigurableProduct: { keyFields: ["uid"] },
  },
});

// Persist cache to device storage for offline access
await persistCache({
  cache,
  storage: new AsyncStorageWrapper(AsyncStorage),
  maxSize: 10 * 1024 * 1024, // 10MB
});

Network-Aware Fetching

import NetInfo from "@react-native-community/netinfo";

async function fetchWithNetworkAwareness<T>(
  query: DocumentNode,
  variables: Record<string, unknown>
): Promise<T> {
  const netState = await NetInfo.fetch();

  if (!netState.isConnected) {
    // Return cached data only
    return client.readQuery({ query, variables });
  }

  const fetchPolicy = netState.type === "cellular" && !netState.isInternetReachable
    ? "cache-first"
    : "cache-and-network";

  const { data } = await client.query({ query, variables, fetchPolicy });
  return data;
}

Performance Optimization

Server-Side Query Complexity Limits

Protect the Magento backend from expensive queries:

// app/etc/env.php
'graphql' => [
    'query_complexity' => 300,
    'query_depth' => 10,
],

Response Compression

Enable gzip compression on the Magento server for GraphQL responses:

# nginx.conf
location /graphql {
    gzip on;
    gzip_types application/json;
    gzip_min_length 256;
    proxy_pass http://magento_backend;
}

GraphQL JSON responses compress extremely well — typical 60-80 percent size reduction.

Image Optimization for Mobile

Request appropriately sized images using Magento's resize parameters:

query {
  products(filter: { category_uid: { eq: "MjA=" } }) {
    items {
      small_image {
        url  # Returns full-size image
      }
      thumbnail {
        url  # Returns thumbnail-size image
      }
    }
  }
}

On the mobile client, use the thumbnail URL for list views and the full image URL for detail views. Implement progressive image loading with blur placeholders for a smooth experience on slow connections.

Best Practices

  • Use query batching to combine multiple small queries into a single HTTP request
  • Implement infinite scroll pagination instead of loading all products at once
  • Cache product catalog data aggressively — prices and stock can have shorter TTL
  • Prefetch the next page of products while the user scrolls for seamless experience
  • Monitor GraphQL query performance with custom server monitoring metrics
  • Use persisted queries in production to reduce request payload size and improve security
  • Test on real devices over throttled connections to validate performance

A well-optimized GraphQL integration delivers native-quality performance in mobile commerce applications while leveraging the full power of the Magento 2 commerce engine.

Need help with this?

Our team handles this kind of work daily. Let us take care of your infrastructure.