Hydrogen
Hydrogen is Shopify's SDK for building storefronts in the JavaScript framework of your choice. It includes a typed Storefront API client, request handlers, and tools for cart, products, collections, search, customer accounts, analytics, and Shop Pay, with React and Vue bindings.
Anchor to Getting startedGetting started
Hydrogen works in a server-rendered JavaScript storefront built with the framework of your choice. You need Storefront API access for the store you want to connect.
Create a project with your framework, then run the setup command in the project folder. If you run the command interactively in an empty folder instead, it offers to create a storefront from the Hydrogen template.
You can also use a template to deploy a full storefront using either React Router or Next.js. To learn more, refer to Get started with Hydrogen.
Add Hydrogen to a project
Anchor to How Hydrogen worksHow Hydrogen works
Hydrogen runs on both sides of your storefront. On the server, the Storefront API client queries Shopify, and request handling serves Shopify's routes, like the cart endpoint, before your framework's router.
In the browser, stores hold the state that changes while a customer is on the page, like the cart. If you're building with React or Vue, bindings connect the stores to your components.
The two sides connect through the routes that handleShopifyRoutes serves.
Your code imports Hydrogen at runtime from the following entry points:
| Entry point | Runs in | Contains |
|---|---|---|
@shopify/hydrogen | Server and browser | The Storefront API client, request handling, server handlers, core stores, and utilities. |
@shopify/hydrogen/react | Browser and server rendering | The React bindings. |
@shopify/hydrogen/vue | Browser and server rendering | The Vue bindings. |
@shopify/hydrogen/customer-account | Server | Customer account login, sessions, errors, and the Customer Account API client. |
@shopify/hydrogen/vite | Vite | The local HTTPS plugin. |
Anchor to Query the Storefront APIQuery the Storefront API
Create a Storefront API client for each request on the server, then query the client with gql documents. The request context passes the customer's cookies, IP address, and declared $country and $language localization variables to the Storefront API. Each query returns data typed against the Storefront API schema.
Every request runs through Hydrogen's request handling before it reaches your router.
Query the Storefront API
Anchor to Query the Customer Account APIQuery the Customer Account API
The Customer Account API serves the signed-in customer's orders, profile, and addresses. Customers sign in with Shopify customer accounts, and each Customer Account API request sends the customer's access token.
Create one session with createCustomerSession at module scope, and pass the session to createCustomerAccountServerHandlers. The handlers serve the login, authorize, refresh, and logout routes under /account, and keep the cart's buyer identity matched to the signed-in customer.
In an account page, read the access token with getAccessToken, and query with a Customer Account API client. When the session has no access token, send the customer to the login route.
Query the Customer Account API
Anchor to Handle requestsHandle requests
Hydrogen's request handling runs around your framework's router. Before your router, handleShopifyRoutes serves the routes that every Shopify storefront needs, like checkout and your cart handlers. After your router, handleShopifyRedirects checks the store's URL redirects for any page that returns a 404.
Handle a request
Anchor to Serve the cart endpointServe the cart endpoint
createCartServerHandlers() returns the handlers for the /api/cart route. They read the cart ID from a cookie, run the matching cart query or mutation, and return JSON to the cart store. When a form is submitted without JavaScript, they redirect back to the page that sent it.
To register the handlers, pass them to handleShopifyRoutes in the handlers array as shown in the server.ts example.
The handlers carry your cart query's types to the browser.
Serve the cart endpoint
cart-handlers.ts
import {createCartServerHandlers} from '@shopify/hydrogen';
export const cartHandlers = createCartServerHandlers();server.ts
import {handleShopifyRoutes} from '@shopify/hydrogen';
import {cartHandlers} from './cart-handlers';
// In your request handler, before your router
const shopifyRoute = handleShopifyRoutes({
request,
requestContext,
storefrontClient: storefront,
sessionManager,
handlers: [cartHandlers],
});
if (shopifyRoute) return shopifyRoute;Anchor to Change the cart with cart formsChange the cart with cart forms
You change the cart by submitting a form. Each form has an intent, like add, remove, or set, and the fields that the intent needs, like a variant ID or a cart line ID.
The cart store handles the submission, updates the cart state right away, and sends the change through Standard Actions, which ShopifyScripts loads, to your cart endpoint.
Add a variant to the cart
JavaScript
// <form id="add-to-cart" method="post" action="/api/cart">
// <input type="hidden" name="merchandiseId" value="gid://shopify/ProductVariant/1">
// <button type="submit" name="intent" value="add">Add to cart</button>
// </form>
const form = document.querySelector('#add-to-cart');
form.addEventListener('submit', (event) => {
event.preventDefault();
cart.handleFormSubmit(event);
});React
import {useCartForm} from './cart';
export function AddToCart({variantId}: {variantId: string}) {
const {formProps, register} = useCartForm();
return (
<form {...formProps()}>
<input type="hidden" {...register('merchandiseId', {value: variantId})} />
<button type="submit" {...register('add')}>
Add to cart
</button>
</form>
);
}Vue
<script setup lang="ts">
import {useCartForm} from './cart';
defineProps<{variantId: string}>();
const {formProps, register} = useCartForm();
</script>
<template>
<form v-bind="formProps()">
<input type="hidden" v-bind="register('merchandiseId', {value: variantId})" />
<button type="submit" v-bind="register('add')">Add to cart</button>
</form>
</template>Anchor to Use UI bindingsUse UI bindings
If you're building with React or Vue, you can use bindings to wrap the core stores in providers, components, and framework-native state.
For React, you pass a hook a selector function like (state) => state.data.totalQuantity, and the component re-renders only when that value changes.
For Vue, you pass a composable a selector function, and it returns a ref (Vue's reactive value) that updates only when the selected value changes.
Frameworks without bindings use the core stores directly. In the browser, load Shopify's storefront scripts, then call connect() so the store listens for Standard Actions cart events. Any script on the page can change the cart through these events.
Show the cart count
JavaScript
import {configureCartEndpoint, createCartStore} from '@shopify/hydrogen';
configureCartEndpoint('/api/cart');
const cart = createCartStore({initialData});
cart.connect();
cart.subscribe((state) => {
document.querySelector('#cart-count').textContent = String(
state.data.totalQuantity,
);
});React
// cart.ts
import {createCartComponents} from '@shopify/hydrogen/react';
import type {cartHandlers} from './cart-handlers';
export const {CartProvider, useCart, useCartForm} =
createCartComponents<typeof cartHandlers>();
// App.tsx
import type {CartDataFromHandlers} from '@shopify/hydrogen';
import {CartProvider, useCart} from './cart';
import type {cartHandlers} from './cart-handlers';
function CartCount() {
const totalQuantity = useCart((state) => state.data.totalQuantity);
return <span>{totalQuantity}</span>;
}
export function App({
initialCart,
}: {
initialCart: CartDataFromHandlers<typeof cartHandlers> | null;
}) {
return (
<CartProvider initialData={{cart: initialCart}}>
<CartCount />
</CartProvider>
);
}Vue
<!-- CartCount.vue -->
<script setup lang="ts">
// cart.ts calls createCartComponents from @shopify/hydrogen/vue
import {useCart} from './cart';
const totalQuantity = useCart((state) => state.data.totalQuantity);
</script>
<template>
<span>{{ totalQuantity }}</span>
</template>
<!-- App.vue -->
<script setup lang="ts">
import type {CartDataFromHandlers} from '@shopify/hydrogen';
import {CartProvider} from './cart';
import type {cartHandlers} from './cart-handlers';
import CartCount from './CartCount.vue';
defineProps<{initialCart: CartDataFromHandlers<typeof cartHandlers> | null}>();
</script>
<template>
<CartProvider :initial-data="{cart: initialCart}">
<CartCount />
</CartProvider>
</template>Anchor to VersioningVersioning
Hydrogen 2026-10 uses version 2026-10 of the Storefront API and the Customer Account API.