Proxy
Catalyst uses a Next.js Proxy to support key features in storefront requests. Proxy is the Next.js 16 name for what earlier versions called Middleware. Catalyst moved from middleware.ts to proxy.ts in Catalyst 1.5.0.
On Native Hosting, Commerce Hosting setup renames proxy.ts back to middleware.ts (exporting middleware with the edge runtime), because the OpenNext Cloudflare adapter doesn’t support the Node.js-only proxy.ts. The chain and configuration described on this page are the same; look for them in middleware.ts. See Native Hosting: Getting Started.
The proxy chain
Proxy code runs before a route is rendered, and provides an entry point for common tasks like authentication, rewrites, and redirects.
proxy.ts in the storefront root directory composes the individual proxies Catalyst uses into a single chain with composeProxies. Each request passes through them in order, and any proxy can return a response early instead of continuing down the chain:
If you customize the chain, keep withUcpProxy first. Several later proxies depend on headers set by earlier ones (for example, withChannelId reads the locale that withIntl resolves), so keep their relative order too.
Exclude paths from the proxy
URL patterns the proxy shouldn’t run on are configured in the config exported by proxy.ts. By default, static files such as sitemaps and robots.txt are excluded, along with API routes. UCP endpoints are matched separately, so the api exclusion keeps applying to every other API route:
For example, if you’ve created a custom route for URLs starting with /product-configure that doesn’t need the proxy, add it to the exclusions in the first pattern:
With UCP proxy
AI agents discover and call the Universal Commerce Protocol (UCP) on your storefront’s public domain, but UCP is served by the BigCommerce platform, not by Catalyst. The withUcpProxy proxy forwards both UCP surfaces to the store’s channel on BigCommerce:
/.well-known/ucp: the discovery document/api/ucp/*: the checkout endpoints, for every HTTP method
It runs first in the chain so that locale rewriting, route resolution, and anonymous session creation are all bypassed for UCP requests. Keep in mind:
- Headers: only the headers the UCP REST transport spec defines are forwarded in either direction. This includes the agent’s credentials and signatures, because UCP authenticates the calling agent at the platform rather than at Catalyst.
- Trailing slashes: the trailing slash is stripped before a UCP path is forwarded. BigCommerce answers a trailing slash with a redirect to the bare path, which an agent would resolve against your storefront domain and send straight back.
- Configuration: the proxy forwards to the channel identified by
BIGCOMMERCE_STORE_HASHandBIGCOMMERCE_CHANNEL_ID, so no extra environment variables are needed. If either is unset, UCP requests return a502. - Customized proxies: if you’ve customized
proxy.ts, make surewithUcpProxyis the first argument tocomposeProxiesand/api/ucp/:path*is inconfig.matcher. Without the matcher entry,/api/ucp/*requests never reach the proxy and return a404.
The UCP proxy was added in Catalyst 1.12.0.
With auth
The withAuth proxy is a wrapper over a minimal implementation of Auth.js, formerly NextAuth.js. This provides Catalyst with session management for shoppers’ carts and customers’ logged-in states. By default, it uses JWT cookies to avoid obligatory dependency on any persistence layer on the storefront itself. You may wish to extend this functionality to store more information in a session or add a persistence layer yourself for more flexibility and control over shopper sessions. See Sessions.
With GraphQL proxy
Catalyst’s own GraphQL requests run server-side, but some client-side libraries need to call the GraphQL Storefront API from the browser. For example, checkout-sdk-js does this to render wallet buttons. The withGraphqlProxy proxy lets these libraries send requests through your storefront domain, so no storefront token is exposed in the browser.
The proxy handles a request only when both of the following are true. Any other request continues down the chain unchanged:
- The path is
/graphql. - The
x-catalyst-graphql-proxy-requesterheader is set to an allow-listed value. Onlycheckout-sdk-jsis allowed by default.
Matching requests must use POST; any other method gets a 405.
The proxy forwards the query and variables to BigCommerce, authenticated with the BIGCOMMERCE_STOREFRONT_UNAUTHENTICATED_TOKEN private token. For signed-in customers, it also passes along the customer access token from the session, so customer-specific data like customer group pricing still resolves. Proxied responses aren’t cached.
The Catalyst CLI doesn’t set BIGCOMMERCE_STOREFRONT_UNAUTHENTICATED_TOKEN. If your store offers wallet payment methods (such as PayPal) on the cart page, or you allow other libraries to use the proxy, create the token and add it to your environment variables, or requests through the GraphQL proxy fail.
To allow another client-side library to use the proxy, add its identifier to the ALLOWED_REQUESTERS list in proxies/with-graphql-proxy.ts, and have the library send that value in the x-catalyst-graphql-proxy-requester header. Keep the list short: every allow-listed requester can run arbitrary GraphQL Storefront API queries with the unauthenticated token.
The GraphQL proxy was added in Catalyst 1.7.0.
With routes
The withRoutes proxy overrides the default Next.js file-based routing behavior to provide support for certain BigCommerce features in a way that allows changes users make with the store control panel and APIs to have the expected effect on the storefront.
For example, consider this SEO-friendly URL path:
In a hypothetical store, this is the URL path set on a product, but the path itself doesn’t indicate that it belongs to a product. And based on the file path of the route at app/[locale]/(default)/product/[slug]/page.tsx, the URL pattern Next.js actually expects is similar to the following example:
Despite the param name [slug], what the route expects in the segment is a product entity ID. The withRoutes proxy sends the path /fancy-high-top to BigCommerce using the GraphQL Storefront API’s route() node to determine the entity (in this case, a product) that corresponds with the supplied path. It then performs an internal Next.js rewrite to the entity-specific path /product/123, resulting in the page being rendered by the appropriate route.
As a result, you can use any URL pattern BigCommerce supports, from /fancy-high-top to /product/fancy-high-top to /shoes/high-tops/fancy-high-top. Any URL assigned to an object’s node using either the store control panel or APIs works as expected on the Catalyst storefront, including 301 redirects.
The withRoutes proxy also checks the storefront status so that when a control panel or API user takes a storefront down for MAINTENANCE or sets it to LAUNCHED, the live storefront reflects the change without waiting for a rebuild of the Next.js application.
Performance and KV store configuration
Using the withRoutes proxy introduces a performance cost, since it requires an additional blocking API request to render site pages.
Although path-to-entity mappings can be cached, the proxy can’t use the Data Cache that caches fetched data in other parts of Catalyst. Instead, a separate caching backend must be used. Catalyst uses a caching implementation that’s flexible for multiple KV adapters.
Route caching on Native Hosting and Vercel
Route caching works out of the box on both documented hosts, with no external KV store or extra configuration:
- Native Hosting: each project gets its own Cloudflare Workers KV namespace, bound to the deployment automatically.
- Vercel: route caching uses the Vercel Runtime Cache.
On any other host, set UPSTASH_REDIS_REST_URL and UPSTASH_REDIS_REST_TOKEN to cache routes in Upstash. Without one of these, route data is cached only in memory, which isn’t shared across server instances.
If your Catalyst storefront does not rely on control panel or API-configured URLs, and you do not need storefront status checks, you can safely remove the withRoutes proxy to improve performance.
For projects where URL structures need to be tightly controlled, consider defining routes at build time or implementing custom routing strategies.