---
title: createStorefrontClient
description: This function extends createStorefrontClient from Hydrogen React.
api_version: 2026-04
api_name: hydrogen
source_url:
  html: https://shopify.dev/docs/api/hydrogen/2023-07/utilities/createstorefrontclient
  md: https://shopify.dev/docs/api/hydrogen/2023-07/utilities/createstorefrontclient.md
---

# createStorefrontClient

This function extends `createStorefrontClient` from [Hydrogen React](https://shopify.dev/docs/api/hydrogen-react/utilities/createstorefrontclient). The additional arguments enable internationalization (i18n), caching, and other features particular to React Router and Oxygen.

The returned storefront client includes methods for proxying requests (`forward`, `isStorefrontApiUrl`) and collecting tracking information (`setCollectedSubrequestHeaders`).

Learn more about [data fetching in Hydrogen](https://shopify.dev/docs/custom-storefronts/hydrogen/data-fetching/fetch-data).

#### Parameters

**`HydrogenClientProps<TI18n> & StorefrontClientProps`**

### HydrogenClientProps

* **cache**

  **Cache**

  An instance that implements the [Cache API](https://developer.mozilla.org/en-US/docs/Web/API/Cache)

* **i18n**

  **TI18n**

  An object containing a country code and language code

* **logErrors**

  **boolean | ((error?: Error) => boolean)**

  Whether it should print GraphQL errors automatically. Defaults to true

* **storefrontHeaders**

  **StorefrontHeaders**

  Storefront API headers. If on Oxygen, use `getStorefrontHeaders()`

* **storefrontId**

  **string**

  The globally unique identifier for the Shop

* **waitUntil**

  **WaitUntil**

  The `waitUntil` function is used to keep the current request/response lifecycle alive even after a response has been sent. It should be provided by your platform.

### StorefrontClientProps

* **contentType**

  **'json' | 'graphql'**

  Customizes which `"content-type"` header is added when using `getPrivateTokenHeaders()` and `getPublicTokenHeaders()`. When fetching with a `JSON.stringify()`-ed `body`, use `"json"`. When fetching with a `body` that is a plain string, use `"graphql"`. Defaults to `"json"`

  Can also be customized on a call-by-call basis by passing in `'contentType'` to both `getPrivateTokenHeaders({...})` and `getPublicTokenHeaders({...})`, for example: `getPublicTokenHeaders({contentType: 'graphql'})`

* **privateStorefrontToken**

  **string**

  The Storefront API delegate access token. Refer to the [authentication](https://shopify.dev/api/storefront#authentication) and [delegate access token](https://shopify.dev/apps/auth/oauth/delegate-access-tokens) documentation for more details.

* **publicStorefrontToken**

  **string**

  The Storefront API access token. Refer to the [authentication](https://shopify.dev/api/storefront#authentication) documentation for more details.

* **storeDomain**

  **string**

  The host name of the domain (eg: `{shop}.myshopify.com`).

* **storefrontApiVersion**

  **string**

  The Storefront API version. This should almost always be the same as the version Hydrogen React was built for. Learn more about Shopify [API versioning](https://shopify.dev/api/usage/versioning) for more details.

### HydrogenClientProps

* cache

  An instance that implements the \[Cache API]\(https://developer.mozilla.org/en-US/docs/Web/API/Cache)

  ```ts
  Cache
  ```

* i18n

  An object containing a country code and language code

  ```ts
  TI18n
  ```

* logErrors

  Whether it should print GraphQL errors automatically. Defaults to true

  ```ts
  boolean | ((error?: Error) => boolean)
  ```

* storefrontHeaders

  Storefront API headers. If on Oxygen, use \`getStorefrontHeaders()\`

  ```ts
  StorefrontHeaders
  ```

* storefrontId

  The globally unique identifier for the Shop

  ```ts
  string
  ```

* waitUntil

  The \`waitUntil\` function is used to keep the current request/response lifecycle alive even after a response has been sent. It should be provided by your platform.

  ```ts
  WaitUntil
  ```

### StorefrontClientProps

* contentType

  Customizes which \`"content-type"\` header is added when using \`getPrivateTokenHeaders()\` and \`getPublicTokenHeaders()\`. When fetching with a \`JSON.stringify()\`-ed \`body\`, use \`"json"\`. When fetching with a \`body\` that is a plain string, use \`"graphql"\`. Defaults to \`"json"\` Can also be customized on a call-by-call basis by passing in \`'contentType'\` to both \`getPrivateTokenHeaders({...})\` and \`getPublicTokenHeaders({...})\`, for example: \`getPublicTokenHeaders({contentType: 'graphql'})\`

  ```ts
  'json' | 'graphql'
  ```

* privateStorefrontToken

  The Storefront API delegate access token. Refer to the \[authentication]\(https://shopify.dev/api/storefront#authentication) and \[delegate access token]\(https://shopify.dev/apps/auth/oauth/delegate-access-tokens) documentation for more details.

  ```ts
  string
  ```

* publicStorefrontToken

  The Storefront API access token. Refer to the \[authentication]\(https://shopify.dev/api/storefront#authentication) documentation for more details.

  ```ts
  string
  ```

* storeDomain

  The host name of the domain (eg: \`{shop}.myshopify.com\`).

  ```ts
  string
  ```

* storefrontApiVersion

  The Storefront API version. This should almost always be the same as the version Hydrogen React was built for. Learn more about Shopify \[API versioning]\(https://shopify.dev/api/usage/versioning) for more details.

  ```ts
  string
  ```

#### Returns

* **storefront**

  **StorefrontForDoc\<TI18n>**

### StorefrontForDoc

* cache

  The cache instance passed in from the \`createStorefrontClient\` argument.

  ```ts
  Cache
  ```

* CacheCustom

  Re-export of \[\`CacheCustom\`]\(/docs/api/hydrogen/utilities/cachecustom).

  ```ts
  (overrideOptions: AllCacheOptions) => AllCacheOptions
  ```

* CacheLong

  Re-export of \[\`CacheLong\`]\(/docs/api/hydrogen/utilities/cachelong).

  ```ts
  (overrideOptions?: AllCacheOptions) => AllCacheOptions
  ```

* CacheNone

  Re-export of \[\`CacheNone\`]\(/docs/api/hydrogen/utilities/cachenone).

  ```ts
  () => NoStoreStrategy
  ```

* CacheShort

  Re-export of \[\`CacheShort\`]\(/docs/api/hydrogen/utilities/cacheshort).

  ```ts
  (overrideOptions?: AllCacheOptions) => AllCacheOptions
  ```

* generateCacheControlHeader

  Re-export of \[\`generateCacheControlHeader\`]\(/docs/api/hydrogen/utilities/generatecachecontrolheader).

  ```ts
  (cacheOptions: AllCacheOptions) => string
  ```

* getApiUrl

  Creates the fully-qualified URL to your store's GraphQL endpoint. See \[\`getStorefrontApiUrl\` in Hydrogen React]\(/docs/api/hydrogen-react/2026-04/utilities/createstorefrontclient#:\~:text=storeDomain-,getStorefrontApiUrl,-(props%3F%3A) for more details.

  ```ts
  (props?: Partial<Pick<StorefrontClientProps, "storefrontApiVersion" | "storeDomain">>) => string
  ```

* getPrivateTokenHeaders

  Returns an object that contains headers that are needed for each query to Storefront API GraphQL endpoint for API calls made from a server. See \[\`getPrivateTokenHeaders\` in Hydrogen React]\(/docs/api/hydrogen-react/2026-04/utilities/createstorefrontclient#:\~:text=storefrontApiVersion-,getPrivateTokenHeaders,-(props%3F%3A) for more details.

  ```ts
  (props?: Partial<Pick<StorefrontClientProps, "contentType">> & Pick<StorefrontClientProps, "privateStorefrontToken"> & { buyerIp?: string; }) => Record<string, string>
  ```

* getPublicTokenHeaders

  Returns an object that contains headers that are needed for each query to Storefront API GraphQL endpoint. See \[\`getPublicTokenHeaders\` in Hydrogen React]\(/docs/api/hydrogen-react/2026-04/utilities/createstorefrontclient#:\~:text=%27graphql%27.-,getPublicTokenHeaders,-(props%3F%3A) for more details.

  ```ts
  (props?: Partial<Pick<StorefrontClientProps, "contentType">> & Pick<StorefrontClientProps, "publicStorefrontToken">) => Record<string, string>
  ```

* getShopifyDomain

  Creates the fully-qualified URL to your myshopify.com domain. See \[\`getShopifyDomain\` in Hydrogen React]\(/docs/api/hydrogen-react/2026-04/utilities/createstorefrontclient#:\~:text=StorefrontClientReturn-,getShopifyDomain,-(props%3F%3A) for more details.

  ```ts
  (props?: Partial<Pick<StorefrontClientProps, "storeDomain">>) => string
  ```

* i18n

  The \`i18n\` object passed in from the \`createStorefrontClient\` argument.

  ```ts
  TI18n
  ```

* mutate

  The function to run a mutation on Storefront API.

  ```ts
  <TData = any>(mutation: string, options: StorefrontMutationOptionsForDocs) => Promise<TData & StorefrontError>
  ```

* query

  The function to run a query on Storefront API.

  ```ts
  <TData = any>(query: string, options: StorefrontQueryOptionsForDocs) => Promise<TData & StorefrontError>
  ```

### AllCacheOptions

Override options for a cache strategy.

* maxAge

  The maximum amount of time in seconds that a resource will be considered fresh. See \`max-age\` in the \[MDN docs]\(https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control#:\~:text=Response%20Directives-,max%2Dage,-The%20max%2Dage).

  ```ts
  number
  ```

* mode

  The caching mode, generally \`public\`, \`private\`, or \`no-store\`.

  ```ts
  string
  ```

* sMaxAge

  Similar to \`maxAge\` but specific to shared caches. See \`s-maxage\` in the \[MDN docs]\(https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control#s-maxage).

  ```ts
  number
  ```

* staleIfError

  Indicate that the cache should serve the stale response if an error occurs while revalidating the cache. See \`stale-if-error\` in the \[MDN docs]\(https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control#stale-if-error).

  ```ts
  number
  ```

* staleWhileRevalidate

  Indicate that the cache should serve the stale response in the background while revalidating the cache. See \`stale-while-revalidate\` in the \[MDN docs]\(https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control#stale-while-revalidate).

  ```ts
  number
  ```

### NoStoreStrategy

* mode

  ```ts
  string
  ```

### StorefrontMutationOptionsForDocs

* displayName

  The name of the query for debugging in the Subrequest Profiler.

  ```ts
  string
  ```

* headers

  Additional headers for this query.

  ```ts
  HeadersInit
  ```

* storefrontApiVersion

  Override the Storefront API version for this query.

  ```ts
  string
  ```

* variables

  The variables for the GraphQL mutation statement.

  ```ts
  Record<string, unknown>
  ```

### StorefrontError

* errors

  ```ts
  StorefrontApiErrors
  ```

### StorefrontApiErrors

```ts
JsonGraphQLError[] | undefined
```

### JsonGraphQLError

* extensions

  Reserved for implementors to extend the protocol however they see fit, and hence there are no additional restrictions on its contents.

  ```ts
  { [key: string]: unknown; }
  ```

* locations

  If an error can be associated to a particular point in the requested GraphQL document, it should contain a list of locations.

  ```ts
  { line: number; column: number; }[]
  ```

* message

  ```ts
  string
  ```

* name

  ```ts
  string
  ```

* path

  If an error can be associated to a particular field in the GraphQL result, it \_must\_ contain an entry with the key \`path\` that details the path of the response field which experienced the error. This allows clients to identify whether a null result is intentional or caused by a runtime error.

  ```ts
  (string | number)[]
  ```

* stack

  ```ts
  string
  ```

### StorefrontQueryOptionsForDocs

* cache

  The cache strategy for this query. Default to max-age=1, stale-while-revalidate=86399.

  ```ts
  CachingStrategy
  ```

* displayName

  The name of the query for debugging in the Subrequest Profiler.

  ```ts
  string
  ```

* headers

  Additional headers for this query.

  ```ts
  HeadersInit
  ```

* storefrontApiVersion

  Override the Storefront API version for this query.

  ```ts
  string
  ```

* variables

  The variables for the GraphQL query statement.

  ```ts
  Record<string, unknown>
  ```

### CachingStrategy

Use the \`CachingStrategy\` to define a custom caching mechanism for your data. Or use one of the pre-defined caching strategies: CacheNone, CacheShort, CacheLong.

* maxAge

  The maximum amount of time in seconds that a resource will be considered fresh. See \`max-age\` in the \[MDN docs]\(https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control#:\~:text=Response%20Directives-,max%2Dage,-The%20max%2Dage).

  ```ts
  number
  ```

* mode

  The caching mode, generally \`public\`, \`private\`, or \`no-store\`.

  ```ts
  string
  ```

* sMaxAge

  Similar to \`maxAge\` but specific to shared caches. See \`s-maxage\` in the \[MDN docs]\(https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control#s-maxage).

  ```ts
  number
  ```

* staleIfError

  Indicate that the cache should serve the stale response if an error occurs while revalidating the cache. See \`stale-if-error\` in the \[MDN docs]\(https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control#stale-if-error).

  ```ts
  number
  ```

* staleWhileRevalidate

  Indicate that the cache should serve the stale response in the background while revalidating the cache. See \`stale-while-revalidate\` in the \[MDN docs]\(https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control#stale-while-revalidate).

  ```ts
  number
  ```

Examples

### Examples

* #### Example code

  ##### JavaScript

  ```js
  import {createStorefrontClient} from '@shopify/hydrogen';
  import {
    createRequestHandler,
    getStorefrontHeaders,
  } from '@shopify/hydrogen/oxygen';
  export default {
    async fetch(request, env, executionContext) {
      /* Create a Storefront client with your credentials and options */
      const {storefront} = createStorefrontClient({
        /* Cache API instance */
        cache: await caches.open('hydrogen'),
        /* Runtime utility in serverless environments */
        waitUntil: (p) => executionContext.waitUntil(p),
        /* Private Storefront API token for your store */
        privateStorefrontToken: env.PRIVATE_STOREFRONT_API_TOKEN,
        /* Public Storefront API token for your store */
        publicStorefrontToken: env.PUBLIC_STOREFRONT_API_TOKEN,
        /* Your store domain: "{shop}.myshopify.com" */
        storeDomain: env.PUBLIC_STORE_DOMAIN,
        /**
         * Storefront API headers containing:
         * - buyerIp: The IP address of the customer.
         * - requestGroupId: A unique ID to group all the logs for this request.
         * - cookie: The 'cookie' header from the request.
         */
        storefrontHeaders: getStorefrontHeaders(request),
      });

      const handleRequest = createRequestHandler({
        build: remixBuild,
        mode: process.env.NODE_ENV,
        /* Inject the Storefront client in the Remix context */
        getLoadContext: () => ({storefront}),
      });

      return handleRequest(request);
    },
  };
  ```

  ##### TypeScript

  ```ts
  import {createStorefrontClient} from '@shopify/hydrogen';
  import * as serverBuild from 'virtual:react-router/server-build';
  import {
    createRequestHandler,
    getStorefrontHeaders,
  } from '@shopify/hydrogen/oxygen';

  export default {
    async fetch(
      request: Request,
      env: Record<string, string>,
      executionContext: ExecutionContext,
    ) {
      /* Create a Storefront client with your credentials and options */
      const {storefront} = createStorefrontClient({
        /* Cache API instance */
        cache: await caches.open('hydrogen'),
        /* Runtime utility in serverless environments */
        waitUntil: (p: Promise<unknown>) => executionContext.waitUntil(p),
        /* Private Storefront API token for your store */
        privateStorefrontToken: env.PRIVATE_STOREFRONT_API_TOKEN,
        /* Public Storefront API token for your store */
        publicStorefrontToken: env.PUBLIC_STOREFRONT_API_TOKEN,
        /* Your store domain: "{shop}.myshopify.com" */
        storeDomain: env.PUBLIC_STORE_DOMAIN,
        /**
         * Storefront API headers containing:
         * - buyerIp: The IP address of the customer.
         * - requestGroupId: A unique ID to group all the logs for this request.
         * - cookie: The 'cookie' header from the request.
         */
        storefrontHeaders: getStorefrontHeaders(request),
      });

      const handleRequest = createRequestHandler({
        build: serverBuild,
        mode: process.env.NODE_ENV,
        /* Inject the Storefront client in the Remix context */
        getLoadContext: () => ({storefront}),
      });

      return handleRequest(request);
    },
  };
  ```

***

## Related

[- CacheNone](https://shopify.dev/docs/api/hydrogen/2026-04/utilities/caching/cachenone)

[- CacheShort](https://shopify.dev/docs/api/hydrogen/2026-04/utilities/caching/cacheshort)

[- CacheLong](https://shopify.dev/docs/api/hydrogen/2026-04/utilities/caching/cachelong)

[- CacheCustom](https://shopify.dev/docs/api/hydrogen/2026-04/utilities/caching/cachecustom)

[- InMemoryCache](https://shopify.dev/docs/api/hydrogen/2026-04/utilities/caching/inmemorycache)

***