Vercel and Shopify are rebuilding Hydrogen

Hydrogen made headless storefronts easy to ship, but not portable. At Vercel Ship 26 in New York, we announced that we are working with Shopify to rebuild it from the ground up, a shared bet on a more open web.

The new version is open source and runtime agnostic, meaning it can run anywhere JavaScript does. You can build with Svelte, Nuxt, Next.js or even bring your own custom framework.
Our strategy includes three layers: core, client and server.
The core
Core is the JavaScript we all used to write for the Shopify API, and never shared. Now it lives in one place.
Take formatMoney. The open web already solved most of this with Intl.NumberFormat.
1const price = new Intl.NumberFormat("en-US", {2 style: "currency",3 currency: "USD",4}).format(19.99); // "$19.99"But the Shopify API doesn't hand you a number. It responds with a custom type, MoneyV2, and the amount is a signed decimal number serialized as a string.
1import { formatMoney, type MoneyV2 } from "@shopify/hydrogen";2
3export function formatPrice(money: MoneyV2, locale = "en-US") {4 return formatMoney(money, { locale }).toString(); // $19.995}The result is the same, but you’re not writing or maintaining the glue code anymore. When the API changes, the upgrade is trivial.
Centralize the core and you fix each bug once, ship improvements to everyone, and get back to building.
The client
Rendering what the core returns involves the same repeated decisions. Cart state is the obvious one.
1import { createContext, useContext, useState, useCallback } from "react";2
3const CartContext = createContext(null);4
5export function CartProvider({ children }) {6 const [cart, setCart] = useState(null);7
8 const addLine = useCallback(async (variantId, quantity) => {9 // custom code that we all wrote ourselves10 }, []);11 const updateLine = useCallback(async (variantId, quantity) => {12 // custom code that we all wrote ourselves13 }, []);14 const removeLine = useCallback(async (variantId, quantity) => {15 // custom code that we all wrote ourselves16 }, []);17
18 // applyDiscount, note, currency, error state, cross-tab sync, refetch on focus, etc.19
20 return (21 <CartContext.Provider value={{ cart, pending, addLine }}>22 {children}23 </CartContext.Provider>24 );25}26
27export const useCart = () => useContext(CartContext);Custom code for managing cart state with React
Anyone who's built a commerce app has written a version of this. Different code every time, all chasing the same things.
With Hydrogen, the client layer now handles the cart. State management becomes one import.
1import { createCartComponents } from "@shopify/hydrogen/react";2
3const { useCartForm } = createCartComponents();4
5function AddToCartButton({ variantId }) {6 const { formProps, register } = useCartForm();7
8 return (9 <form {...formProps()}>10 <input11 type="hidden"12 {...register("merchandiseId", { value: variantId })}13 />14 <button {...register("add")}>Add to cart</button>15 </form>16 );17}With Hydrogen the cart state management is a single import
Centralize this and you get the best practices for free, so you can spend your time on the parts that are actually yours to build. It's available for React today on the Hydrogen preview branch, with more frameworks coming.
The server
Developers need full-stack access to build storefronts that scale without sacrificing performance. Static content should serve instantly from a CDN while dynamic data like inventory streams in.
The open-source community solved this with frameworks like Next.js, Nuxt, and SvelteKit: full-stack capabilities with no lock-in to a proprietary runtime.
Say your storefront caches product queries with on-demand revalidation. You write the GraphQL query. Hydrogen gives you a type-safe client. Next.js handles caching, and you get full-stack frameworks plus the headless Shopify API with none of the glue code.