Pick Hydrogen when you want Shopify’s cart handler, sub-request caching and Customer Account API already wired up, and you are happy hosting on Oxygen. Pick Next.js when the storefront is one part of a larger application, or when you need a runtime and a React version that Shopify has not pinned for you.
Both talk to the same Storefront API and both hand the buyer off to Shopify’s hosted checkout at the end. The decision is not about what you can build. It is about how much commerce plumbing you write yourself, and who controls your upgrade schedule.
Shopify Hydrogen vs Next.js: what actually differs
Hydrogen is not a framework in its own right. It is a package of components and utilities layered on React Router, which does the routing, data loading and server rendering. What Shopify adds is the commerce-shaped part.
Open the type definitions of @shopify/hydrogen (2026.4.5 as of August 2026) and the shape of the offer is obvious. createHydrogenContext builds a request context holding a Storefront API client, a cart handler and a Customer Account client. createCartHandler returns an object with create, addLines, updateLines, removeLines, updateDiscountCodes, updateGiftCardCodes, updateBuyerIdentity, updateSelectedDeliveryOption, setMetafields and the rest. CartForm and useOptimisticCart give you optimistic line updates without writing the reducer. There is an Analytics component, getShopAnalytics, getSitemap, storefrontRedirect for Shopify’s URL redirect table, and createContentSecurityPolicy with a matching useNonce.
A product route ends up looking like this:
import type {LoaderFunctionArgs} from 'react-router';
const PRODUCT_QUERY = `#graphql
query Product($handle: String!) {
product(handle: $handle) {
id
title
description
}
}
`;
export async function loader({context, params}: LoaderFunctionArgs) {
const {storefront} = context;
const {product} = await storefront.query(PRODUCT_QUERY, {
variables: {handle: params.handle!},
cache: storefront.CacheLong(),
});
return {product};
}
Next.js gives you none of that and does not pretend to. What it gives you instead is React Server Components, Server Actions, a routing model your team probably already knows, and the freedom to put an admin panel, a marketing site and a storefront in one deployment. Vercel maintains Next.js Commerce as a Shopify-only starter, which is a reasonable place to steal cart code from, though it is a starter and not a theme.
How does Hydrogen’s sub-request caching work?
Every call through storefront.query passes through a cache keyed on the query and its variables, stored in the runtime’s Cache API instance. This is the piece people underestimate when they cost out a migration.
The documented strategies are exact. CacheShort() emits public, max-age=1, stale-while-revalidate=9. CacheLong() emits public, max-age=3600, stale-while-revalidate=82800, which is an hour fresh and a day stale. CacheNone() emits no-store. CacheCustom() takes a mode and a maxAge and does what you tell it. When you pass no cache option at all, the sub-request still gets public, max-age=1, stale-while-revalidate=86399, so the safe default is already cached rather than already uncached.
That default is the part to watch. Anything customer-specific has to opt out explicitly:
const {customer} = await storefront.query(CUSTOMER_QUERY, {
variables: {customerAccessToken: context.session.get('customerAccessToken')},
cache: storefront.CacheNone(),
});
On Next.js you build the same behaviour out of the fetch cache or, under Cache Components, out of use cache and cacheLife. Both work. Neither is handed to you with sensible commerce defaults, and the failure mode is quieter: a missing CacheNone() in Hydrogen is a one-line fix, while a wrongly cached authenticated fetch in an App Router app can be harder to spot. We wrote up the mechanics in our guide to the use cache directive.
Does Hydrogen lock you into Oxygen hosting?
Not formally. Shopify documents self-hosting on Vercel, Netlify, Fly.io and Cloudflare Workers, and the same page carries a warning worth reading twice: the guide “might not be compatible with features introduced in Hydrogen version 2025-05 and above”. You also become responsible for supplying the cache and waitUntil implementations that createHydrogenContext expects from the platform.
So it is portable in the way a house is portable. Possible, expensive, and nobody is going to help you.
Staying on Oxygen means accepting a specific runtime. It runs on Cloudflare’s workerd, so if you have ever shipped to Workers the constraints will be familiar, and our comparison of the two Cloudflare deployment targets covers the same runtime shape. Worker startup has to complete in 400 milliseconds or less. Memory tops out at 128 MB, and going over can mean dropped requests, so large response bodies have to be streamed. caches.default is unsupported. Node’s Web Crypto implementation is not the one you get, so any code assuming it needs changing.
In exchange, Oxygen is included at no extra charge on paid Shopify plans, and deployments stay reachable for a minimum of six months with the ten most recent per environment kept indefinitely. For a store already paying for Shopify, the hosting line item goes to zero.
What do you have to build yourself on Next.js?
The cart, mostly. Cart ID cookie handling, create-on-first-add, line mutations, buyer identity, discount and gift card codes, delivery option selection, and the optimistic UI on top. That is a fortnight of work done properly, and it is work that has already been done for you in the other column.
Then customer accounts. Hydrogen ships createCustomerAccountClient with an OAuth flow that expects an /account/authorize route and handles token refresh and logged-out redirects. Doing that against the Customer Account API by hand is not hard, but it is fiddly and security-relevant, which is a poor combination.
One thing that does travel: @shopify/hydrogen-react (2026.4.3) peer-depends only on react, react-dom and vite, with no dependency on Hydrogen or Oxygen. Its components and hooks work in a Next.js app. You lose the server-side utilities, not the presentational ones.
Which React and React Router versions does Hydrogen pin?
This is the trade-off nobody puts in the comparison table. Hydrogen 2026.4.5 declares peer dependencies on react-router and @react-router/dev at ~7.16.0. React Router 7.16.0 was published on 28 May 2026; 8.0.0 followed on 17 June 2026. React is pinned to ^18.3.1 || ~19.0.3 || ~19.1.4 || ^19.2.3, and Vite to ^5.1.0 || ^6.2.1 || ^7.0.0 || ^8.0.0.
You upgrade when Shopify upgrades. Next.js has the same property with respect to React, but the gap between a React release and a Next.js release that accepts it is usually shorter than the gap between a React Router major and a Hydrogen calendar version that takes it.
Which one to pick
If the project is a Shopify store and the team is under about five people, take Hydrogen. Free hosting on Oxygen, a cart you did not write, and caching defaults tuned by people who watch Storefront API traffic all day are worth more than framework independence you will never exercise. Scaffold it with npm create @shopify/hydrogen@latest, keep the generated routes, and spend the saved fortnight on merchandising.
Take Next.js when the storefront is not the whole product. A subscription portal, a booking flow, a members’ area or a content site that happens to sell things will fight Hydrogen’s route conventions, and you will end up rebuilding half of Next.js inside it. Take it also if you are already deep in the App Router and the cost of a second mental model across the team exceeds the cost of a cart implementation.
The one case where the answer is neither: a store with fewer than a few hundred SKUs and no unusual requirements. Online Store 2.0 with a good theme will beat both of them to launch by a month, and headless is a decision to defer until something concrete forces it. We say the same thing to most people who ask us about an ecommerce build.