Catalyst version 1.5.0 Release Notes
We are excited to announce the release of Catalyst v1.5.0, which upgrades to Next.js 16, migrates to the proxy pattern with Node.js 24, adds product gallery pagination, uncached product inventory fetching, canonical URL and hreflang SEO support, cart inventory messaging, and a collection of bug fixes and improvements.
For additional details, you can refer to the Catalyst 1.5 changeset.
Next.js 16
Catalyst has been upgraded from Next.js 15 to Next.js 16. This release bumps next to ^16.1.6, aligns React and peer dependencies, migrates away from deprecated unstable_* cache APIs, updates TypeScript configuration for Next.js 16 compatibility, and resolves new deprecation lint errors.
Cache API migration
Next.js 16 stabilizes the cache invalidation APIs that Catalyst previously consumed as unstable imports. This release replaces all usage:
unstable_expireTag→revalidateTag(fromnext/cache)unstable_expirePath→revalidatePath(fromnext/cache)
The function signatures are identical — no behavioral changes to cache invalidation.
Before:
After:
TypeScript configuration
Next.js 16 requires updated TypeScript compiler options. The tsconfig.json has been updated:
moduleResolutionchanged to"bundler"modulechanged to"nodenext"
If you have customized your tsconfig.json, ensure these values are set to avoid type resolution issues.
Dynamic imports in the client module
To support Next.js 16’s module resolution behavior, the BigCommerce API client (core/client/index.ts) now uses dynamic import() calls for next/headers, next/navigation, and next-intl/server instead of static top-level imports. This prevents AsyncLocalStorage context poisoning that occurs when next.config.ts eagerly evaluates the full module graph during config resolution.
This change is internal to the client module — all consumer imports remain unchanged.
Deprecation lint fixes
Next.js 16 introduces stricter linting for HTML best practices. This release resolves deprecation warnings for:
- Legacy
<img>elements (replaced withnext/imageor explicitly opted out) - Missing
rel="noopener noreferrer"on externaltarget="_blank"links
Middleware to proxy migration
Next.js 16 deprecates middleware.ts in favor of proxy.ts to clarify its network-boundary purpose. This release migrates Catalyst to the new proxy pattern:
middleware.tshas been renamed toproxy.tsexport const middlewarehas been renamed toexport const proxy- The internal
middlewares/directory has been renamed toproxies/
The proxy runs on the Node.js runtime (not Edge), which requires Node.js 24 or later. Catalyst now enforces this via the engines field in package.json as well as the .nvmrc Node.js version configuration file in the root of the Catalyst repository.
Internal middleware composition (composeMiddlewares → composeProxies, all with-*.ts files) follows the same patterns — only the naming and entry point have changed. There are no behavioral changes to auth, redirects, or locale switching.
Migration
To upgrade your Catalyst storefront to Next.js 16:
- Update
nextto^16.0.0in yourpackage.jsonand install dependencies. - Replace any usage of
unstable_expireTagwithrevalidateTagandunstable_expirePathwithrevalidatePathfromnext/cache. - Update
tsconfig.jsonto use"moduleResolution": "bundler"and"module": "nodenext". - Rename
middleware.tstoproxy.tsand changeexport const middlewaretoexport const proxy. - Rename the
middlewares/directory toproxies/and update any internal imports accordingly. - Ensure you are running Node.js 24 or later.
- Address any Next.js 16 deprecation lint errors (e.g., legacy
<img>elements, missingrel="noopener noreferrer"on external links).
Product gallery pagination
Products with many images now support paginated loading in the gallery. When a product has more images than the initial page load, additional images load in batches as the user scrolls through the thumbnails. Thumbnail images now display horizontally across all viewport sizes.
Migration
- Create the new server action file
core/app/[locale]/(default)/product/[slug]/_actions/get-more-images.tswith a GraphQL query to fetch additional product images with pagination. - Update the product page data fetching in
core/app/[locale]/(default)/product/[slug]/page-data.tsto includepageInfo(withhasNextPageandendCursor) from the images query. - Update
core/app/[locale]/(default)/product/[slug]/page.tsxto pass the new pagination props (pageInfo,productId,loadMoreAction) to theProductDetailcomponent.
Due to the number of changes, it is recommended to use the PR as a reference for migration.
Uncached product inventory fetching
Product inventory data is now fetched with a separate GraphQL query that bypasses caching. This ensures that customers always see real-time stock levels on the product detail page, rather than potentially stale cached inventory counts.
Migration
Rebase the following files with the new release code:
core/app/[locale]/(default)/product/[slug]/page-data.tscore/app/[locale]/(default)/product/[slug]/page.tsx
Canonical URLs and hreflang alternates
Pages now generate proper canonical URLs and hreflang alternate links for SEO. A new getMetadataAlternates helper (core/lib/seo/canonical.ts) fetches the vanity URL via GraphQL and builds canonical and hreflang metadata for each page. The default locale uses no path prefix; other locales use /{locale}/path.
On Vercel preview deployments (VERCEL_ENV=preview), the canonical and hreflang URLs use VERCEL_URL instead of the production vanity URL, preventing preview environments from generating SEO metadata that points to production.
Migration
This change touches many page files to add alternates to their generateMetadata exports. Due to the number of changes, it is recommended to use the PR as a reference for migration. At a high level:
- Create the new
core/lib/seo/canonical.tshelper. - Update the root locale layout (
core/app/[locale]/layout.tsx) to setmetadataBasefrom the vanity URL. - Add
alternates: await getMetadataAlternates(...)togenerateMetadatain each page file (home, product, category, brand, blog, blog post, webpages, gift certificates, compare, and wishlist pages). - Add the
pathfield to brand, blog post, and product GraphQL queries so metadata can build canonical URLs.
Cart line item inventory messaging
The cart page now displays inventory-aware messaging on each line item based on store inventory settings:
- Out-of-stock message when a line item is fully or partially out of stock (if enabled on the store)
- Ready-to-ship quantity (if enabled on the store)
- Backordered quantity (if enabled on the store)
Migration
Rebase the following files with the new release code:
core/app/[locale]/(default)/cart/page-data.tscore/app/[locale]/(default)/cart/page.tsxcore/messages/en.jsoncore/vibes/soul/sections/cart/client.tsx
DOMPurify migration
Catalyst now uses dompurify instead of isomorphic-dompurify, which required JSDOM. JSDOM does not work in edge-runtime environments, and since DOMPurify is only needed on the client for JSON-LD schema sanitization, the isomorphic variant was unnecessary. The ProductReviewSchema component is now a client component.
Migration
- Remove the old dependency and add the new one:
- Update the import in
core/app/[locale]/(default)/product/[slug]/_components/product-review-schema/product-review-schema.tsx:
- Add the
'use client';directive to the top of the same file.
Form field validation translations
Forms now translate validation error messages. Due to the breadth of changes across form components, it is recommended to use the PR as a reference for migration.
Conditional SEO metadata
Optional SEO metadata fields (description, keywords, alternates, openGraph) are now only included in generateMetadata return values when they have a value, using conditional spread syntax. Previously, these fields could be set to null or an empty string, which caused Next.js to render empty <meta> tags.
Migration
Update generateMetadata in page files (brand, category, webpages, blog, blog post, product) to use conditional spread syntax for optional metadata fields:
Bug fixes and improvements
- Makeswift layout shift: Upgraded
@makeswift/runtimeto^0.26.3, which replaces<Suspense>with the React<Activity>API to eliminate layout shift when loading Makeswift pages and when client-side navigating between Makeswift and non-Makeswift pages. - Gift certificate amount selection: Fixed an issue where the
GiftCertificateCardwas not updating when selecting a new amount on the gift certificate purchase form. - Cart shipping form state values: The cart shipping estimator now uses state abbreviations instead of
entityIdfor state values. The shipping API expects abbreviations, and usingentityIdcaused form submissions to fail. Certain US military states that share the same abbreviation (AE) are now filtered to prevent duplicate key issues. - Translation updates: Updated translations across the storefront.
Release Tags
We have published new tags for the Core and Makeswift versions of Catalyst. Target these tags to pull the latest code:
And as always, you can pull the latest stable release with these tags: