---
title: Storefront API
description: "How the template calls Shopify's Storefront GraphQL API - the fetch client, query patterns, caching, and error handling."
url: "https://shop-docs.labs.vercel.dev/docs/reference/storefront-api"
docs_index: /llms.txt
lastUpdated: 2026-10-18
type: reference
prerequisites:
  - /docs/getting-started
---

> For an index of all documentation, see [/llms.txt](/llms.txt).

The template uses the framework-agnostic [Shopify Hydrogen](https://www.npmjs.com/package/@shopify/hydrogen) SDK for Storefront GraphQL API queries and mutations. It runs on Next.js, not the Hydrogen React Router framework. Next.js owns page routing, rendering, and public-data caching; Hydrogen supplies Shopify API clients and commerce handlers.

Configure the store domain, public token, and API version with the variables in [Environment Variables](/docs/reference/env-vars). Grant the scopes in [Storefront API Permissions](/docs/reference/storefront-api-permissions).

The Customer Account API uses a separate endpoint and schema. Enabling authentication requires `SHOPIFY_CUSTOMER_ACCOUNT_API_CLIENT_ID`, `SHOPIFY_CUSTOMER_ACCOUNT_API_CLIENT_SECRET`, and a separate app-generated `CUSTOMER_ACCOUNT_SESSION_SECRET` for encrypted session cookies. Keep both secrets server-only. Its documents use `gql` from `@shopify/hydrogen/customer-account` and are validated separately from Storefront documents.

## Write and validate operations

Define each operation with Hydrogen's `gql()` tag and pass dynamic values as GraphQL variables. Do not interpolate runtime values or conditional fields into the document. Compose shared selections by passing fragment documents as the second argument.

Result and variable types are inferred from the document, so the request wrapper returns typed data without a hand-written response type. Include Shopify's `@inContext` directive when localized pricing or content depends on country and language. The wrapper defaults `$country` and `$language` to `shopConfig.localization.country` and `shopConfig.localization.language`. The separate `shopConfig.localization.locale` controls display formatting; it does not select a market or currency. Currency comes from Shopify.

Omit the operation's `locale` option to use the deployment settings. For an explicit commerce context, pass a `{ country, language }` object, not a formatting locale string. Keep that object in cached operation arguments when results vary by market or language:

```ts
import { gql } from "@shopify/hydrogen";

const GET_PRODUCT_QUERY = gql(`#graphql
  query getProduct(
    $handle: String!
    $country: CountryCode
    $language: LanguageCode
  ) @inContext(country: $country, language: $language) {
    product(handle: $handle) {
      id
      title
    }
  }
`);

const response = await storefront.request(GET_PRODUCT_QUERY, {
  locale: { country: "US", language: "EN" },
  variables: { handle },
});
```

Validate current field names, arguments, and types with Shopify AI Toolkit. Then use the [`shopify-graphql-reference` skill](/docs/skills/shopify-graphql-reference) for template integration conventions. The skill is not a schema source.

## Caching

Public-data operations use Next.js Cache Components and cache tags; the Hydrogen client does not replace that cache layer. Choose caching by data sensitivity and behavior:

| Data or operation                                          | Cache contract                                                |
| ---------------------------------------------------------- | ------------------------------------------------------------- |
| Public product, collection, menu, or content data          | Cache and invalidate when Shopify changes                     |
| Public results that vary by filters, search, or pagination | Share only when the cache key includes every varying input    |
| Cart, session, authorization, or customer data             | Keep request-scoped or private; never place in a public cache |
| Mutations                                                  | Do not cache                                                  |

Configure `POST /api/webhooks/shopify` as described in [Webhooks](/docs/anatomy/webhooks) to refresh cached products and collections after edits. The handler supports product, collection, and metaobject topics; other content needs its own invalidation strategy or cache expiry.

## Mutations

Storefront cart forms submit to Hydrogen's `POST /api/cart` handler through the Next.js proxy, not to cart Server Actions. Mutations are uncached and return the updated cart for Hydrogen's client store to reconcile. Cart updates do not invalidate the public catalog cache.

The optional shopping assistant uses the same handlers on the server, and the shopper's cart updates in the browser after the assistant changes it. See [Cart](/docs/anatomy/cart) for shopper behavior and limits.

Never cache cart IDs, customer data, session data, or authenticated responses in a shared public cache.

## Errors and missing resources

Storefront requests throw on transport failures and timeouts. The request wrapper returns GraphQL errors alongside data; read operations check the result with `assertStorefrontOk`. This check throws when no data is returned or Shopify reports throttling or a server error, and logs a warning for other errors that accompany partial data.

A missing resource is not an API failure. Read operations return `undefined`, `null`, or an empty list when the requested resource does not exist.

Set `DEBUG_SHOPIFY=true` to include structured Storefront and Customer Account API operation timings in server logs. Warnings and errors remain enabled when debug logging is off.

---

For a semantic overview of all documentation, see [/sitemap.md](/sitemap.md)

For an index of all available documentation, see [/llms.txt](/llms.txt)

For agent-facing discovery, including API and MCP surfaces, see [/agents.md](/agents.md)