---
title: Customize a cart handler
description: >-
  Customize a cart handler to perform different tasks and return different cart
  fields.
source_url:
  html: >-
    https://shopify.dev/docs/storefronts/headless/legacy/hydrogen/cart/customize-cart-handler
  md: >-
    https://shopify.dev/docs/storefronts/headless/legacy/hydrogen/cart/customize-cart-handler.md
api_name: hydrogen
---

Legacy Hydrogen

These pages refer to Hydrogen versions 2026-04 and earlier. For versions 2026-10 and later, refer to the latest [Hydrogen docs](https://shopify.dev/docs/storefronts/hydrogen). If you're not using the latest version of Hydrogen, then we recommend that you migrate your storefront. To learn more, refer to [Migrate to the latest version of Hydrogen](https://shopify.dev/docs/storefronts/hydrogen/migrate).

# Customize a cart handler

The cart handler is an interface that allows you to easily make cart query and mutation requests to the Storefront API. It creates a new cart if one doesn't already exist, and provides default built-in cart queries.

This guide shows you how to customize a cart handler. You can customize a cart handler to return different cart query fields, override existing cart query functions, and add new cart query functions.

***

## Requirements

* You've completed the [quickstart guide](https://shopify.dev/docs/storefronts/headless/legacy/hydrogen/getting-started).
* You've [set up a cart handler](https://shopify.dev/docs/storefronts/headless/legacy/hydrogen/cart/setup).

***

## Customize the return cart fields

The `createCartHandler` includes a default query fragment. Pass a custom `cartQueryFragment` if you need additional data from the Storefront API. See the [default `CartApiQuery` fragment](https://github.com/Shopify/hydrogen/blob/f4c30410d29291ea5550d85a5976d822da0f24b4/packages/hydrogen/src/cart/queries/cartGetDefault.ts) for reference. In this example, we added the `note` field.

## File

## server.js

##### JavaScript

```jsx
const cart = createCartHandler({
  storefront,
  getCartId: cartGetIdDefault(request.headers),
  setCartId: cartSetIdDefault(),
  cartQueryFragment: CART_QUERY_FRAGMENT, // Your custom cart query fragment
});

/**
 * cartQueryFragment requirements:
  *
 * - Must be named `CartApiQuery`
 * - Only have access to the following query variables:
 *   - $cartId: ID!
 *   - $country: CountryCode
 *   - $language: LanguageCode
 *   - $numCartLines: Int
  **/
  const CART_QUERY_FRAGMENT = `#graphql
  fragment CartApiQuery on Cart {
    note
    id
    checkoutUrl
    totalQuantity
    buyerIdentity {
      countryCode
      customer {
        id
        email
        firstName
        lastName
        displayName
      }
      email
      phone
    }
    lines(first: $numCartLines) {
      edges {
        node {
          id
          quantity
          attributes {
            key
            value
          }
          cost {
            totalAmount {
              amount
              currencyCode
            }
            amountPerQuantity {
              amount
              currencyCode
            }
            compareAtAmountPerQuantity {
              amount
              currencyCode
            }
          }
          merchandise {
            ... on ProductVariant {
              id
              availableForSale
              compareAtPrice {
                ...CartApiMoney
              }
              price {
                ...CartApiMoney
              }
              requiresShipping
              title
              image {
                ...CartApiImage
              }
              product {
                handle
                title
                id
              }
              selectedOptions {
                name
                value
              }
            }
          }
        }
      }
    }
    cost {
      subtotalAmount {
        ...CartApiMoney
      }
      totalAmount {
        ...CartApiMoney
      }
      totalDutyAmount {
        ...CartApiMoney
      }
      totalTaxAmount {
        ...CartApiMoney
      }
    }
    note
    attributes {
      key
      value
    }
    discountCodes {
      applicable
      code
    }
  }

  fragment CartApiMoney on MoneyV2 {
    currencyCode
    amount
  }

  fragment CartApiImage on Image {
    id
    url
    altText
    width
    height
  }
`;
```

##### TypeScript

```jsx
const cart = createCartHandler({
  storefront,
  getCartId: cartGetIdDefault(request.headers),
  setCartId: cartSetIdDefault(),
  cartQueryFragment: CART_QUERY_FRAGMENT, // Your custom cart query fragment
});

/**
 * cartQueryFragment requirements:
  *
 * - Must be named `CartApiQuery`
 * - Only have access to the following query variables:
 *   - $cartId: ID!
 *   - $country: CountryCode
 *   - $language: LanguageCode
 *   - $numCartLines: Int
  **/
  const CART_QUERY_FRAGMENT = `#graphql
  fragment CartApiQuery on Cart {
    note
    id
    checkoutUrl
    totalQuantity
    buyerIdentity {
      countryCode
      customer {
        id
        email
        firstName
        lastName
        displayName
      }
      email
      phone
    }
    lines(first: $numCartLines) {
      edges {
        node {
          id
          quantity
          attributes {
            key
            value
          }
          cost {
            totalAmount {
              amount
              currencyCode
            }
            amountPerQuantity {
              amount
              currencyCode
            }
            compareAtAmountPerQuantity {
              amount
              currencyCode
            }
          }
          merchandise {
            ... on ProductVariant {
              id
              availableForSale
              compareAtPrice {
                ...CartApiMoney
              }
              price {
                ...CartApiMoney
              }
              requiresShipping
              title
              image {
                ...CartApiImage
              }
              product {
                handle
                title
                id
              }
              selectedOptions {
                name
                value
              }
            }
          }
        }
      }
    }
    cost {
      subtotalAmount {
        ...CartApiMoney
      }
      totalAmount {
        ...CartApiMoney
      }
      totalDutyAmount {
        ...CartApiMoney
      }
      totalTaxAmount {
        ...CartApiMoney
      }
    }
    note
    attributes {
      key
      value
    }
    discountCodes {
      applicable
      code
    }
  }

  fragment CartApiMoney on MoneyV2 {
    currencyCode
    amount
  }

  fragment CartApiImage on Image {
    id
    url
    altText
    width
    height
  }
`;
```

Provide `cartMutateFragment` to customize what data is returned from mutation queries. See the [default `CartApiMutation` fragment](https://github.com/Shopify/hydrogen/blob/f4c30410d29291ea5550d85a5976d822da0f24b4/packages/hydrogen/src/cart/queries/cart-fragments.ts) for reference. In this example, we added the `checkoutUrl` field.

## File

## server.js

##### JavaScript

```jsx
const cart = createCartHandler({
  storefront,
  getCartId: cartGetIdDefault(request.headers),
  setCartId: cartSetIdDefault(),
  cartMutateFragment: CART_MUTATE_FRAGMENT, // Your custom cart mutate fragment
});

/**
 * cartMutateFragment requirements:
  *
 * - Must be named `CartApiMutation`
 * - Only have access to the following query variables:
 *   - $cartId: ID!
 *   - $country: CountryCode
 *   - $language: LanguageCode
  **/
  const CART_MUTATE_FRAGMENT = `#graphql
  fragment CartApiMutation on Cart {
    id
    totalQuantity
    checkoutUrl
  }
`;
```

##### TypeScript

```jsx
const cart = createCartHandler({
  storefront,
  getCartId: cartGetIdDefault(request.headers),
  setCartId: cartSetIdDefault(),
  cartMutateFragment: CART_MUTATE_FRAGMENT, // Your custom cart mutate fragment
});

/**
 * cartMutateFragment requirements:
  *
 * - Must be named `CartApiMutation`
 * - Only have access to the following query variables:
 *   - $cartId: ID!
 *   - $country: CountryCode
 *   - $language: LanguageCode
  **/
  const CART_MUTATE_FRAGMENT = `#graphql
  fragment CartApiMutation on Cart {
    id
    totalQuantity
    checkoutUrl
  }
`;
```

***

## Add custom methods to cart handler

If you have common cart operations that you would like to reuse across your app, you can add custom methods to your cart handler. For example, add and remove an item from the cart at the same time.

## File

## server.js

##### JavaScript

```jsx
const cartQueryOptions = {
  storefront,
  getCartId: cartGetIdDefault(request.headers),
};

const cart = createCartHandler({
  storefront,
  getCartId: cartGetIdDefault(request.headers),
  setCartId: cartSetIdDefault(),
  customMethods: {
    editInLine: async (addLines, removeLineIds, optionalParams) => {
      // Using Hydrogen default cart query methods

      // Add line items
      await cartLinesAddDefault(cartQueryOptions)(addLines, optionalParams);

      // Remove line items
      return await cartLinesRemoveDefault(cartQueryOptions)(
        removeLineIds,
        optionalParams,
      );
    }
  },
});
```

##### TypeScript

```jsx
import {type CartQueryOptions} from '@shopify/hydrogen';

const cartQueryOptions: CartQueryOptions = {
  storefront,
  getCartId: cartGetIdDefault(request.headers),
};

const cart = createCartHandler({
  storefront,
  getCartId: cartGetIdDefault(request.headers),
  setCartId: cartSetIdDefault(),
  customMethods: {
    editInLine: async (addLines, removeLineIds, optionalParams) => {
      // Using Hydrogen default cart query methods

      // Add line items
      await cartLinesAddDefault(cartQueryOptions)(addLines, optionalParams);

      // Remove line items
      return await cartLinesRemoveDefault(cartQueryOptions)(
        removeLineIds,
        optionalParams,
      );
    }
  },
});
```

***

## Override existing cart handler methods

Hydrogen provides out of the box multiple methods for interacting with the cart. You can override any default method with your own logic. For example, you can override the `updateAttributes` to do something custom with cart attributes:

The default cart handler includes basic cart logic. If you override these methods, you need to implement the cart logic as well. For example when adding a line item to a cart, you would need to implement the logic needed to create a cart with the line item.

The following methods include create cart logic::

* `addLines` - If a cart doesn't exist, then create a cart with the line items.
* `setMetafields` - If a cart doesn't exist, then create a cart with the metafields applied.
* `updateAttributes` - If a cart doesn't exist, then create a cart with the attributes applied.
* `updateBuyerIdentity` - If a cart doesn't exist, then create a cart with the buyer identity applied.
* `updateDiscountCode` - If a cart doesn't exist, then create a cart with the discount applied.
* `updateNote` - If a cart doesn't exist, then create a cart with the note applied.

## File

## server.js

##### JavaScript

```jsx
const cart = createCartHandler({
  storefront,
  getCartId: cartGetIdDefault(request.headers),
  setCartId: cartSetIdDefault(),
  customMethods: {
    updateAttributes: async (attributes, optionalParams) => {

      // Do something with attributes

      // Make a mutation query to update cart attributes
      const {cartAttributesUpdate} = await options.storefront.mutate(CART_ATTRIBUTES_UPDATE_MUTATION, {
        variables: {
          cartId: optionalParams?.cartId || options.getCartId(),
          attributes,
        },
      });
      return cartAttributesUpdate;
    },
  },
});

export const CART_ATTRIBUTES_UPDATE_MUTATION = `#graphql
  mutation cartAttributesUpdate(
    $cartId: ID!
    $attributes: [CartAttributeInput!]!
  ) {
    cartAttributesUpdate(cartId: $cartId, attributes: $attributes) {
      cart {
        id
      }
    }
  }
`;
```

##### TypeScript

```jsx
const cart = createCartHandler({
  storefront,
  getCartId: cartGetIdDefault(request.headers),
  setCartId: cartSetIdDefault(),
  customMethods: {
    updateAttributes: async (attributes, optionalParams) => {

      // Do something with attributes

      // Make a mutation query to update cart attributes
      const {cartAttributesUpdate} = await options.storefront.mutate<{
        cartAttributesUpdate: CartQueryData;
      }>(CART_ATTRIBUTES_UPDATE_MUTATION, {
        variables: {
          cartId: optionalParams?.cartId || options.getCartId(),
          attributes,
        },
      });
      return cartAttributesUpdate;
    },
  },
});

export const CART_ATTRIBUTES_UPDATE_MUTATION = `#graphql
  mutation cartAttributesUpdate(
    $cartId: ID!
    $attributes: [CartAttributeInput!]!
  ) {
    cartAttributesUpdate(cartId: $cartId, attributes: $attributes) {
      cart {
        id
      }
    }
  }
`;
```

***
