---
schema_version: "1"
id: 9833b015debe48103135256357dc2fb2cec28b5a7d7d0d4b816b55df6ca30d1c
title: Basket Management
collection: developer
version: current
locale: en-us
portal_url: https://docs.salesforce.com/developer/current/en-us/commerce-cloud/sfnext/guides/sfnext-basket-management.md
canonical_url: https://developer.salesforce.com/docs/commerce/pwa-kit-managed-runtime/guide/sfnext-basket-management.html
source_site: developer.salesforce.com
content_type: documentation
content_hash: 7a61fdc4b3fb4c42e1a5849dfa4474d43e03079525bb397f0266a4f733990ebd
products:
  - Composable Storefront
  - Salesforce APIs
---
# Basket Management

Basket management provides a consistent way to preserve cart state across the server and client while removing the need to fetch or create a basket on every request. Our React Router middleware stores a snapshot of the current basket as a cookie, enabling the basket ID and item count to persist across page refreshes. Full basket state hydration is performed lazily, which helps keep page loads fast.

## Dependencies

| Package        | Version  | Purpose                        |
| -------------- | -------- | ------------------------------ |
| React Router 7 | 7.12.0   | Middleware and context system. |
| React Context  | Built-in | Basket provider state.         |

## Overview

Here's an overview of the basket management process.

1. Middleware initializes context with a cookie snapshot on every request.
2. Root loader passes the snapshot into the `BasketProvider` without hydrating the full basket.
3. Client components hydrate lazily via `useBasket()` when full basket data is required.
4. Middleware updates or deletes the cookie based on the final basket state after loaders or actions finish.

```mermaid
sequenceDiagram
    participant Browser
    box Server
        participant Middleware
        participant Loader
        participant SCAPI
    end

    Browser->>Middleware: Request with basket cookie
    Middleware->>Middleware: Parse snapshot into context
    opt Eager mode only
        Middleware->>SCAPI: getOrCreateBasket(basketId)
        SCAPI-->>Middleware: Full basket payload
    end
    Middleware->>Loader: Continue to loader
    Loader-->>Browser: Return basket snapshot for provider
    Middleware->>Middleware: Update cookie snapshot on response
```

```mermaid
sequenceDiagram
    participant Browser
    box Client
        participant Provider
    end
    participant SCAPI

    Browser->>Provider: useBasket() called
    Provider->>SCAPI: getOrCreateBasket(basketId)
    SCAPI-->>Provider: Full basket payload
    Provider-->>Browser: Context hydrated
```

## Basket Middleware

The server-side middleware is the source of truth for basket state and cookie management.

### Configuration Options

`createBasketMiddleware` accepts these optional settings.

- `mode`: `'lazy'` (default) or `'eager'` hydration.
- `cookieName`: Override the basket cookie name (default `__sfdc_basket`).
- `cookieDurationRegistered`: Cookie duration (TTL) in ms for registered shoppers.
- `cookieDurationGuest`: Cookie duration (TTL) in ms for guest shoppers.
- `currency`: Currency used when creating a basket.
- `calculateBasketSnapshot`: Add custom fields to the cookie snapshot.

**note:** The cookie duration (TTL) default values are set to the same default values for your ECOM instance. If you have customized those values, you'll want to ensure that you are properly configuring these values to be in alignment.

**Context value:**

- `basketResourceContext`: snapshot, basket, hydration state, and error.

**Modes:**

- `lazy` (default): Only the snapshot is set. Full basket is fetched on demand.
- `eager`: Middleware hydrates basket before calling `next()`.

**Cookie snapshot characteristics:**
The cookie snapshot:

- Is stored in `__sfdc_basket`.
- Includes `basketId`, `totalItemCount`, and `uniqueProductCount`.
- Contains optional custom fields via `calculateBasketSnapshot`.

Here's a minimal cookie snapshot configuration for the default lazy mode.

```typescript
// root.tsx
import createBasketMiddleware from "@/middlewares/basket.server";

export const middleware = [
  // ...other middleware
  createBasketMiddleware(),
];
```

### Context Getters and Mutations

Use these helpers in loaders or actions (server) to interact with the request-scoped basket.

```typescript
import {
  getBasket,
  getBasketSnapshot,
  ensureBasketId,
  updateBasketResource,
  destroyBasket,
} from "@/middlewares/basket.server";

export async function loader({ context }) {
  const snapshot = getBasketSnapshot(context);
  const basketResource = await getBasket(context, { ensureBasket: true });
  return { snapshot, basket: basketResource.current };
}

export async function action({ context }) {
  const basketId = await ensureBasketId(context);
  // ...perform SCAPI calls to mutate basket
  updateBasketResource(context, (current) => ({
    ...current,
    basketId: basketId ?? current?.basketId,
  }));
}
```

## Basket Provider and Client Hooks

`BasketProvider` keeps basket data in React context for the client. It receives the snapshot from the root loader, exposes lazy hydration, and updates through hooks.

### Provider Configuration

`BasketProvider` accepts:

- `snapshot`: Cookie-safe basket snapshot for initial render.
- `basket`: Full basket payload (optional, for eager client hydration).

### Provider State Shape

The provider stores:

- `snapshot`: Cookie-safe basket summary.
- `current`: Full basket payload (when hydrated).
- `hydrated`: Whether hydration has been attempted.
- `error`: Hydration error info (if any).

The root loader intentionally passes only `basketSnapshot` to avoid eager basket creation.

```typescript
// root.tsx (simplified)
const basketSnapshot = context.get(basketResourceContext)?.snapshot ?? null;

const providers = [
  // ...other providers
  [BasketProvider, { snapshot: basketSnapshot }],
] as const;
```

### Lazy Hydration (`useBasket`)

`useBasket()` triggers a client-side fetch when:

- A snapshot exists (has `basketId`).
- No full basket is yet in context.

**note:** The client-side fetch is useful for components, such as the minicart, that render outside a full page loader and still need full basket data.

```typescript
import { useBasket } from "@/providers/basket";

export function CartBadge() {
  const basket = useBasket();
  return <span>{basket?.totalProductCount ?? 0}</span>;
}
```

### Updating and Resetting the Basket

Use these hooks in client components after mutations or checkout completion. Common use cases include sharing updated basket data across the React app and clearing basket state after order completion. You typically call `useBasketUpdater` after basket actions, such as adding or removing items, or applying or removing promotions. Updates aren't automatically inferred from route loaders because of the default lazy behavior.

```typescript
import { useBasketUpdater, useBasketReset } from "@/providers/basket";

const setBasket = useBasketUpdater();
const resetBasket = useBasketReset();

// After a successful mutation
setBasket(updatedBasket);

// On checkout completion
resetBasket();
```

## Advanced Configuration

Use these options only when needed.

1. **Eager hydration**: Set `mode: 'eager'` if a route always needs a full basket.
2. **Custom snapshot fields**: Add metadata (for example, pickup flags) via `calculateBasketSnapshot`.
3. **Force refresh**: Call `getBasket(context, { ensureBasket: true })` to hydrate server-side before action logic that requires a full basket.

Example custom snapshot:

```typescript
createBasketMiddleware({
  calculateBasketSnapshot: (basket) => ({
    hasShipments: Boolean(basket.shipments?.length),
  }),
});
```

## Basket Lifecycle Summary

| Phase                 | Behavior                                                         | Example                    |
| --------------------- | ---------------------------------------------------------------- | -------------------------- |
| Initial request       | Middleware reads cookie → snapshot only                          | Cart badge shows count.    |
| Full basket data      | Loaded when the route or component explicitly needs it.          | Cart page loader.          |
| Client-side hydration | Happens during basket actions or when the UI needs data.         | `<CartSheet />` component. |
| Updates and cleanup   | Mutations update context/cookie. `destroyBasket()` clears state. | After checkout completion. |
