--- title: Set up a cart handler description: >- Learn how to set up a cart handler to be accessible from Remix's actions and loaders. source_url: html: 'https://shopify.dev/docs/storefronts/headless/hydrogen/cart/setup' md: 'https://shopify.dev/docs/storefronts/headless/hydrogen/cart/setup.md' --- ExpandOn this page * [Requirements](https://shopify.dev/docs/storefronts/headless/hydrogen/cart/setup.md#requirements) * [Step 1: Create a cart instance with create​Hydrogen​Context](https://shopify.dev/docs/storefronts/headless/hydrogen/cart/setup.md#step-1-create-a-cart-instance-with-createhydrogencontext) * [Step 2: Include the app context in the server.​(js|ts)](https://shopify.dev/docs/storefronts/headless/hydrogen/cart/setup.md#step-2-include-the-app-context-in-the-serverjsts) * [Step 3: Decide how you want to manage the cart ID](https://shopify.dev/docs/storefronts/headless/hydrogen/cart/setup.md#step-3-decide-how-you-want-to-manage-the-cart-id) * [Next steps](https://shopify.dev/docs/storefronts/headless/hydrogen/cart/setup.md#next-steps) # Set up a cart handler Note This guide might not be compatible with features introduced in Hydrogen version 2025-05 and above. Check the latest [documentation](https://shopify.dev/docs/api/hydrogen) if you encounter any issues. This guide shows you how to set up a cart handler inside your Hydrogen app. This makes a dynamic `cart` object available on all requests, so it can be read and updated by Remix actions and loaders. Tip These tasks are only required if you're upgrading from a version prior to `2024.7.4`. As of version `2024.7.4`, the Hydrogen project template includes the cart handler by default. *** ## Requirements * You've completed the [quickstart guide](https://shopify.dev/docs/storefronts/headless/hydrogen/getting-started). *** ## Step 1: Create a `cart` instance with `createHydrogenContext` Hydrogen uses [`createHydrogenContext`](https://shopify.dev/docs/api/hydrogen/latest/utilities/createhydrogencontext) to setup a common set of contexts, which includes cart context, that you will need in your Remix loaders and actions. Create a `context.(js|ts)` file. This file should manage all the context that you want to show up in the Remix context. ## File ## /app/lib/context.ts ##### JavaScript ```jsx import {createHydrogenContext} from '@shopify/hydrogen'; import {AppSession} from '~/lib/session'; import {CART_QUERY_FRAGMENT} from '~/lib/fragments'; /** * The context implementation is separate from server.ts * so that type can be extracted for AppLoadContext * */ export async function createAppLoadContext( request, env, executionContext, ) { /** * Open a cache instance in the worker and a custom session instance. */ if (!env?.SESSION_SECRET) { throw new Error('SESSION_SECRET environment variable is not set'); } const waitUntil = executionContext.waitUntil.bind(executionContext); const [cache, session] = await Promise.all([ caches.open('hydrogen'), AppSession.init(request, [env.SESSION_SECRET]), ]); const hydrogenContext = createHydrogenContext({ env, request, cache, waitUntil, session, i18n: {language: 'EN', country: 'US'}, cart: { queryFragment: CART_QUERY_FRAGMENT, }, }); return { ...hydrogenContext, // declare additional Remix loader context }; } ``` ##### TypeScript ```jsx import {createHydrogenContext} from '@shopify/hydrogen'; import {AppSession} from '~/lib/session'; import {CART_QUERY_FRAGMENT} from '~/lib/fragments'; /** * The context implementation is separate from server.ts * so that type can be extracted for AppLoadContext * */ export async function createAppLoadContext( request: Request, env: Env, executionContext: ExecutionContext, ) { /** * Open a cache instance in the worker and a custom session instance. */ if (!env?.SESSION_SECRET) { throw new Error('SESSION_SECRET environment variable is not set'); } const waitUntil = executionContext.waitUntil.bind(executionContext); const [cache, session] = await Promise.all([ caches.open('hydrogen'), AppSession.init(request, [env.SESSION_SECRET]), ]); const hydrogenContext = createHydrogenContext({ env, request, cache, waitUntil, session, i18n: {language: 'EN', country: 'US'}, cart: { queryFragment: CART_QUERY_FRAGMENT, }, }); return { ...hydrogenContext, // declare additional Remix loader context }; } ``` *** ## Step 2: Include the app context in the `server.(js|ts)` In your `server.(js|ts)` file, include your `appLoadContext` inside the Remix request handler. ## File ## server.js ##### JavaScript ```jsx import {createRequestHandler} from '@shopify/remix-oxygen'; import {createAppLoadContext} from '~/lib/context'; /** * Export a fetch handler in module format. */ export default { async fetch( request, env, executionContext ) { try { const appLoadContext = await createAppLoadContext( request, env, executionContext, ); /** * Create a Remix request handler and pass * Hydrogen's Storefront client to the loader context. */ const handleRequest = createRequestHandler({ build: remixBuild, mode: process.env.NODE_ENV, getLoadContext: () => appLoadContext, }); ... ``` ##### TypeScript ```jsx import {createRequestHandler} from '@shopify/remix-oxygen'; import {createAppLoadContext} from '~/lib/context'; /** * Export a fetch handler in module format. */ export default { async fetch( request: Request, env: Env, executionContext: ExecutionContext, ): Promise { try { const appLoadContext = await createAppLoadContext( request, env, executionContext, ); /** * Create a Remix request handler and pass in the * appLoadContext to the Remix's loader context. */ const handleRequest = createRequestHandler({ build: remixBuild, mode: process.env.NODE_ENV, getLoadContext: () => appLoadContext, }); ... ``` If you're using Typescript, then add the return type of `createAppLoadContext` type to `env.d.ts` to have a type association. ## TypeScript env.d.ts ```tsx import type {createAppLoadContext} from '~/lib/context'; declare module '@shopify/remix-oxygen' { interface AppLoadContext extends Awaited> { // to change context type, change the return of createAppLoadContext() instead } } ``` *** ## Step 3: Decide how you want to manage the cart ID Hydrogen provides the following default methods for getting and setting a cart ID: * `cartGetIdDefault(requestHeaders: Headers)`: Retrieves the cart ID from the request header cookie. The cookie name must be `cart`. * `cartSetIdDefault()`: Returns a function that accepts a new cart ID and sets a cookie called `cart=` in the returned `Headers` object. By default, `cartSetIdDefault()` sets a session cookie. This means the cookie disappears when the user closes the browser. Update cookie settings by passing an options object to the `cartSetIdDefault` function. This options object [accepts the same attribute types](https://github.com/lukeed/worktop/blob/master/src/cookie.d.ts) provided by the cookie-parsing interface from the Worktop package dependency. ## File ## /app/lib/context.js ##### JavaScript ```jsx import {cartGetIdDefault, cartSetIdDefault} from '@shopify/hydrogen'; import {CART_QUERY_FRAGMENT} from '~/lib/fragments'; ... const hydrogenContext = createHydrogenContext({ env, request, cache, waitUntil, session, i18n: {language: 'EN', country: 'US'}, cart: { queryFragment: CART_QUERY_FRAGMENT, getId: cartGetIdDefault(request.headers), setId: cartSetIdDefault({ maxage: 60 * 60 * 24 * 365, // One year expiry }), }, }); ``` ##### TypeScript ```jsx import {cartGetIdDefault, cartSetIdDefault} from '@shopify/hydrogen'; import {CART_QUERY_FRAGMENT} from '~/lib/fragments'; ... const hydrogenContext = createHydrogenContext({ env, request, cache, waitUntil, session, i18n: {language: 'EN', country: 'US'}, cart: { queryFragment: CART_QUERY_FRAGMENT, getId: cartGetIdDefault(request.headers), setId: cartSetIdDefault({ maxage: 60 * 60 * 24 * 365, // One year expiry }), }, }); ``` Note The default methods for getting and saving a cart use the cookie name `cart`. This name allows a cart instance to be shared between Liquid and Hydrogen. If you provide custom cookie persistence methods and need to maintain compatibility with a Liquid-coded online store, then make sure to also use the cookie name `cart`. *** ## Next steps * Learn how to [read data from a cart](https://shopify.dev/docs/storefronts/headless/hydrogen/cart/read) * Learn how to [customize your own cart handler](https://shopify.dev/docs/storefronts/headless/hydrogen/cart/customize-cart-handler). *** * [Requirements](https://shopify.dev/docs/storefronts/headless/hydrogen/cart/setup.md#requirements) * [Step 1: Create a cart instance with create​Hydrogen​Context](https://shopify.dev/docs/storefronts/headless/hydrogen/cart/setup.md#step-1-create-a-cart-instance-with-createhydrogencontext) * [Step 2: Include the app context in the server.​(js|ts)](https://shopify.dev/docs/storefronts/headless/hydrogen/cart/setup.md#step-2-include-the-app-context-in-the-serverjsts) * [Step 3: Decide how you want to manage the cart ID](https://shopify.dev/docs/storefronts/headless/hydrogen/cart/setup.md#step-3-decide-how-you-want-to-manage-the-cart-id) * [Next steps](https://shopify.dev/docs/storefronts/headless/hydrogen/cart/setup.md#next-steps)