Skip to main content

Cart server handlers

The cart server handlers serve the /api/cart route, which loads and updates the customer's cart through the Storefront API. Use these functions to register the cart route, load the cart in server loaders, parse cart requests in custom routes, and set the cart cookie.

Import createCartServerHandlers, parseCartRequest, getCart, getCartId, createCartCookie, and CartDataFromQuery from @shopify/hydrogen.

Pass the handlers to handleShopifyRoutes to serve the cart route before your framework's router runs.


Creates the handlers for the /api/cart route, which loads and changes the customer's cart.

The handlers read the cart ID from the cart cookie and set the cookie when they create a cart. A JSON request gets a JSON response, and a form submission gets a 303 redirect to the referring page.

Pass customerSession to connect carts to the logged-in customer. The handlers then need sessionManager and requestContext in their context.

Anchor to options
options
<>

A custom cart fragment and the customer session.

|

The GET and POST handlers to register with handleShopifyRoutes.

The JSON result that the cart GET handler returns. The handler sets private cache headers that keep CDNs and shared caches from storing the cart.

TData
required

The value that Hydrogen serializes as the response body.

'json'
required

Set to json for a JSON response.

Anchor to headers
headers
HeadersInit

Extra headers for the response. Hydrogen sets content-type to application/json and overrides any value you pass.

The response body that the cart GET handler returns.

TCart | null
required

The cart, or null when the request has no cart ID, the cart doesn't exist, or the cart query returns GraphQL errors.

Anchor to errors
errors
Array<{ message: string }>

GraphQL errors from the cart query. The handler also logs the errors on the server.

CartPostResult is the route result that the cart POST handler returns. Check type to tell the results apart:

  • json answers a JSON request with the same fields as CartGetResult. The result's data holds the mutation's cart, userErrors, and warnings.
  • redirect answers a form submission with a 303 redirect to the referring page.
  • error holds a CartError with a code that identifies the failure.

Anchor to shopifyrouteredirectresultShopifyRouteRedirectResult

A route handler result that Hydrogen sends as a redirect response.

Anchor to location
location
string
required

The redirect target. Hydrogen resolves a relative path against the request's origin.

'redirect'
required

Set to redirect for a redirect response.

Anchor to headers
headers
HeadersInit

Extra headers for the redirect response.

Anchor to status
status

The HTTP redirect status. Defaults to 303.

Anchor to shopifyrouteerrorresultShopifyRouteErrorResult

A route handler result that Hydrogen sends as a JSON error response.

Anchor to error
error
TError
required

The error that Hydrogen serializes as the response body's error field.

'error'
required

Set to error for an error response.

Anchor to headers
headers
HeadersInit

Extra headers for the error response. Hydrogen sets content-type to application/json and overrides any value you pass.

Anchor to status
status
number

The HTTP status for the error response. Defaults to 400.

An error that the cart POST handler returns, with a code that identifies the failure.

required

The code that identifies the failure.

Anchor to message
message
string
required

A human-readable error message.

Examples

TypeScript

import {
createCartServerHandlers,
handleShopifyRoutes,
type ShopifyRouteHandlerContext,
} from "@shopify/hydrogen";

export const cartHandlers = createCartServerHandlers();

export function handleRequest(
context: ShopifyRouteHandlerContext,
next: () => Promise<Response>,
) {
const shopifyRoute = handleShopifyRoutes({
...context,
handlers: [cartHandlers],
});
if (shopifyRoute) return shopifyRoute;

return next();
}

Anchor to Cart request helpersCart request helpers

Reads the cart change from a cart request body. Use the function in a custom cart route.

The function accepts application/json, application/x-www-form-urlencoded, and multipart/form-data requests. A JSON request can replace every discount code, and a form submission applies or removes one code.

A form submission always returns a null cart ID. Read the cart ID for a form submission with getCartId.

The function reads the request body, and you can't read the body again afterward. The function throws when the request has an unsupported content type, an unknown intent, or a missing required field, and when a JSON body combines more than one of lines, discountCodes, attributes, and note.

Anchor to request
request
Request
required

The incoming cart request.

Promise<>

The cart change and, for a JSON body, the cart ID.

Fetches a cart by ID from the Storefront API.

Pass a custom cart query to get a cart with that query's fields. Declare an $id variable in the query. The function passes the cart ID as the query's only variable.

When the cart ID is null, the function returns a null cart without a network request. The function throws when the Storefront API request fails.

Anchor to cartId
cartId
string
required

The ID of the cart to fetch, or null to skip the request.

Anchor to storefront
storefront
required

The Storefront API client that runs the cart query.

Anchor to cartQuery
cartQuery

A cart query document that replaces the default cart query.

Promise<<>>

The cart or null, any GraphQL errors, and the Storefront API response headers.

Reads the cart ID from a request.

The function checks the cartId search parameter first, then the cart cookie. The function returns a search parameter value unchanged and adds the gid://shopify/Cart/ prefix to a cookie value.

Anchor to input
input
required

The request or request context that carries the cart ID.

string | null

The cart ID, or null when neither the search parameter nor the cookie has one.

Examples

TypeScript

import { cartQueries, getCartId, parseCartRequest, type StorefrontClient } from "@shopify/hydrogen";

export async function handleCartPost(request: Request, storefrontClient: StorefrontClient) {
const parsed = await parseCartRequest(request).catch(() => null);
if (!parsed) return Response.json({ error: "Invalid cart request" }, { status: 400 });

const cartId = parsed.cartId ?? getCartId(request);
if (!cartId) return Response.json({ error: "No cart exists" }, { status: 404 });

const { action } = parsed;
switch (action.intent) {
case "remove": {
const { data } = await storefrontClient.graphql(cartQueries.cartLinesRemove, {
variables: { cartId, lineIds: action.lineIds },
});
return Response.json(data);
}
case "note-update": {
const { data } = await storefrontClient.graphql(cartQueries.cartNoteUpdate, {
variables: { cartId, note: action.note },
});
return Response.json(data);
}
default:
return Response.json({ error: `Unsupported intent ${action.intent}` }, { status: 400 });
}
}

Creates the Set-Cookie header value that stores the cart ID in the cart cookie.

The cookie holds the cart token without the gid://shopify/Cart/ prefix and expires after 14 days. The cookie sets Path=/ and SameSite=Lax, and leaves out HttpOnly and Secure. Append the value to the response headers to keep the response's other cookies.

Anchor to cartId
cartId
string
required

The cart GID or cart token to store.

The header value that sets the cart cookie.

Examples

TypeScript

import { cartQueries, createCartCookie, type StorefrontClient } from "@shopify/hydrogen";

export async function createCartWithDiscount(code: string, storefrontClient: StorefrontClient) {
const { data } = await storefrontClient.graphql(cartQueries.cartCreate, {
variables: { input: { discountCodes: [code] } },
});
const cart = data?.cartCreate?.cart;

const headers = new Headers({ location: "/" });
if (cart) headers.append("set-cookie", createCartCookie(cart.id));

return new Response(null, { status: 303, headers });
}

Anchor to Server-rendered cartServer-rendered cart

Call cartHandlers.get() in a loader and pass the result's data, or a promise of it, to the initialData prop of the cart provider.


CartDataFromQuery types the cart that a custom cart query returns, such as a loader's return value or a component prop. Pass the query's type, such as CartDataFromQuery<typeof CUSTOM_CART_QUERY>. Your query's cart fields replace the matching fields of the default cart data type. A query without a cart field gets the default cart data type.


Was this page helpful?