shopify-hydrogen
Build a custom Shopify storefront using the Hydrogen React framework with Remix routing and deploy it to Shopify's Oxygen edge hosting
What this skill does
# Shopify Hydrogen
## Overview
Hydrogen is Shopify's official React-based framework for building headless storefronts, built on top of Remix and deployed to Oxygen (Shopify's edge hosting). It provides first-class primitives for the Storefront API — product queries, cart management, customer accounts — alongside Shopify-specific components and hooks that handle caching, streaming, and SEO automatically. This skill covers scaffolding a Hydrogen project, querying the Storefront API, implementing cart functionality, and deploying to Oxygen.
## When to Use This Skill
- When building a custom Shopify storefront with full design and UX control
- When the default Shopify Online Store theme is too limiting for your design requirements
- When you need server-side rendering, streaming, and edge-deployed performance
- When integrating third-party services (loyalty, CMS, personalization) directly into the storefront
- When you want a Shopify-managed backend with a completely custom frontend stack
## Prerequisites & Platform Notes
**This skill is written for custom/headless storefronts** (Node.js, Python, or similar backend). The code examples use TypeScript/Node.js and can be adapted to any stack.
**Shopify**: Shopify Hydrogen is Shopify's headless framework. MACH/composable patterns apply when using Shopify as the commerce backend with a custom frontend, or when mixing Shopify with other best-of-breed services.
**WooCommerce**: WooCommerce can serve as a headless backend via its REST API and WPGraphQL. These patterns apply when decoupling the frontend from WordPress.
**Magento**: Magento's GraphQL API and PWA Studio support headless architectures. These composable patterns apply to Magento as a backend service in a MACH stack.
**You'll need**:
- Node.js 18+ (or adapt to your backend language)
- Redis for caching/queues
- An email sending service (SendGrid, AWS SES, or Postmark)
- CDN (Cloudflare, CloudFront, or Fastly)
## Core Instructions
1. **Scaffold a Hydrogen project**
```bash
npm create @shopify/hydrogen@latest -- --quickstart
# or with options:
npm create @shopify/hydrogen@latest
# Follow prompts: project name, language (TypeScript), mock shop or real credentials
cd my-hydrogen-store
npm run dev
# http://localhost:3000
```
The project structure follows Remix file-based routing:
```
app/
routes/
_index.tsx # Homepage
products.$handle.tsx # Product detail page
collections.$handle.tsx
cart.tsx
components/
lib/
fragments.ts # Reusable GraphQL fragments
server.ts # Hydrogen + Remix entry point
```
2. **Configure Storefront API credentials**
Create a Storefront API token in your Shopify admin under **Apps → Develop apps → Create an app → Storefront API**.
```bash
# .env
SESSION_SECRET="your-session-secret"
PUBLIC_STOREFRONT_API_TOKEN="your-public-token"
PUBLIC_STORE_DOMAIN="your-store.myshopify.com"
PUBLIC_STOREFRONT_API_VERSION="2025-01"
```
The `server.ts` wires Hydrogen into Remix:
```typescript
import {createHydrogenContext} from '@shopify/hydrogen';
const hydrogenContext = createHydrogenContext({
storefront: {
apiVersion: env.PUBLIC_STOREFRONT_API_VERSION,
privateStorefrontToken: env.PRIVATE_STOREFRONT_API_TOKEN,
publicStorefrontToken: env.PUBLIC_STOREFRONT_API_TOKEN,
storeDomain: env.PUBLIC_STORE_DOMAIN,
},
session: HydrogenSession.init(request, [env.SESSION_SECRET]),
});
```
3. **Query the Storefront API**
Hydrogen provides a `storefront.query` method with built-in caching policies.
```typescript
// app/routes/products.$handle.tsx
import {useLoaderData} from '@remix-run/react';
import {json, type LoaderFunctionArgs} from '@shopify/remix-oxygen';
export async function loader({params, context}: LoaderFunctionArgs) {
const {storefront} = context;
const {product} = await storefront.query(PRODUCT_QUERY, {
variables: {handle: params.handle},
cache: storefront.CacheLong(), // Cache at CDN for 24h
});
if (!product) throw new Response('Not Found', {status: 404});
return json({product});
}
const PRODUCT_QUERY = `#graphql
query Product($handle: String!) {
product(handle: $handle) {
id
title
descriptionHtml
featuredImage { url altText width height }
variants(first: 20) {
nodes {
id
title
price { amount currencyCode }
availableForSale
selectedOptions { name value }
}
}
}
}
` as const;
```
4. **Implement cart with Hydrogen cart utilities**
Hydrogen provides server-side cart actions via Remix action functions:
```typescript
// app/routes/cart.tsx
import {CartForm} from '@shopify/hydrogen';
import type {ActionFunctionArgs} from '@shopify/remix-oxygen';
export async function action({request, context}: ActionFunctionArgs) {
const {cart} = context;
const formData = await request.formData();
const {action, inputs} = CartForm.getFormInput(formData);
let result;
switch (action) {
case CartForm.ACTIONS.LinesAdd:
result = await cart.addLines(inputs.lines);
break;
case CartForm.ACTIONS.LinesUpdate:
result = await cart.updateLines(inputs.lines);
break;
case CartForm.ACTIONS.LinesRemove:
result = await cart.removeLines(inputs.lineIds);
break;
default:
throw new Error(`Unhandled cart action: ${action}`);
}
const headers = cart.setCartId(result.cart.id);
return json(result, {headers});
}
// Add to cart form component
export function AddToCartButton({variantId}: {variantId: string}) {
return (
<CartForm
route="/cart"
action={CartForm.ACTIONS.LinesAdd}
inputs={{lines: [{merchandiseId: variantId, quantity: 1}]}}
>
<button type="submit">Add to Cart</button>
</CartForm>
);
}
```
5. **Use Hydrogen caching strategies**
Hydrogen exposes named caching strategies that map to CDN cache-control headers:
```typescript
// Long cache for static catalog data
const {collections} = await storefront.query(COLLECTIONS_QUERY, {
cache: storefront.CacheLong(), // s-maxage=3600, stale-while-revalidate=82800
});
// Short cache for inventory-sensitive data
const {product} = await storefront.query(PRODUCT_WITH_INVENTORY, {
cache: storefront.CacheShort(), // s-maxage=1, stale-while-revalidate=9
});
// No cache for personalized/cart data
const {customer} = await storefront.query(CUSTOMER_QUERY, {
cache: storefront.CacheNone(),
});
// Custom strategy
const {data} = await storefront.query(QUERY, {
cache: storefront.CacheCustom({
mode: 'public',
maxAge: 600,
staleWhileRevalidate: 3000,
}),
});
```
6. **Deploy to Oxygen**
```bash
npm install -g @shopify/cli
shopify hydrogen deploy
# Creates a deployment in your Shopify admin under Online Store → Themes → Headless
```
For CI/CD, use the GitHub Action:
```yaml
# .github/workflows/oxygen.yml
- uses: Shopify/hydrogen-action@v1
with:
shop: ${{ secrets.SHOPIFY_SHOP_DOMAIN }}
token: ${{ secrets.SHOPIFY_CLI_TOKEN }}
```
## Examples
### Collection page with filtering and sorting
```typescript
// app/routes/collections.$handle.tsx
export async function loader({params, request, context}: LoaderFunctionArgs) {
const {storefront} = context;
const url = new URL(request.url);
const sortKey = url.searchParams.get('sort') as ProductCollectionSortKeys | null;
const {collection} = await storefront.query(COLLECTION_QUERY, {
variables: {
handle: params.handle,
first: 24,
sortKey: sortKey ?? 'BEST_SELLING',
revRelated in headless-modern
medusa-development
IncludedExtend the open-source Medusa commerce platform with custom services, event subscribers, and API endpoints for unique business requirements
commerce-api-gateway
IncludedAggregate multiple commerce microservices behind a single API gateway with GraphQL federation, rate limiting, and unified authentication
pwa-storefront
IncludedTurn your store into an installable Progressive Web App with offline product browsing, push notifications, and home screen access for mobile shoppers
commerce-js-integration
IncludedBuild a lightweight headless store using the Commerce.js SDK for product display, cart management, and checkout without a heavy backend
composable-commerce
IncludedArchitect a modern store using MACH principles — independent microservices, API-first integrations, cloud-native hosting, and headless frontend
saleor-development
IncludedBuild and extend Saleor's GraphQL-based headless commerce platform with custom apps, webhook handlers, and dashboard UI customizations