Install
$ agentstack add skill-dragnoir-shopify-agent-skills-headless-hydrogen ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ● Network access Used
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ● Environment & secrets Used
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
Headless Commerce with Hydrogen
When to use this skill
Use this skill when:
- Building a custom headless storefront
- Using Hydrogen framework for e-commerce
- Deploying to Oxygen (Shopify's edge hosting)
- Working with the Storefront API
- Creating high-performance, custom storefronts
- Integrating Shopify with custom tech stacks
What is Hydrogen?
Hydrogen is Shopify's official headless commerce framework built on:
- React Router - For routing and data loading
- React - Component-based UI
- GraphQL - Data fetching from Storefront API
- Oxygen - Global edge deployment (free hosting)
Key Benefits
- Build-ready components - Pre-built commerce components
- Free hosting - Deploy to Oxygen at no extra cost
- Fast by default - SSR, progressive enhancement, nested routes
- Shopify-native - Deep integration with Shopify APIs
Getting Started
1. Create a Hydrogen App
# Create new Hydrogen project
npm create @shopify/hydrogen@latest
# Follow the prompts:
# - Choose a template (Demo store, Hello World, Skeleton)
# - Enter your store URL
# - Select JavaScript or TypeScript
2. Project Structure
hydrogen-app/
├── app/
│ ├── components/ # React components
│ ├── routes/ # Page routes
│ │ ├── _index.tsx # Home page
│ │ ├── products.$handle.tsx # Product page
│ │ └── collections.$handle.tsx
│ ├── styles/ # CSS files
│ ├── entry.client.tsx # Client entry
│ └── entry.server.tsx # Server entry
├── public/ # Static assets
├── .env # Environment variables
├── hydrogen.config.ts # Hydrogen config
└── package.json
3. Environment Setup
# .env
SESSION_SECRET=your-session-secret
PUBLIC_STOREFRONT_API_TOKEN=your-storefront-api-token
PUBLIC_STORE_DOMAIN=your-store.myshopify.com
4. Start Development
npm run dev
Core Concepts
Routes and Data Loading
// app/routes/products.$handle.tsx
import { useLoaderData, type LoaderFunctionArgs } from "@remix-run/react";
export async function loader({ params, context }: LoaderFunctionArgs) {
const { storefront } = context;
const { handle } = params;
const { product } = await storefront.query(PRODUCT_QUERY, {
variables: { handle },
});
if (!product) {
throw new Response("Not Found", { status: 404 });
}
return { product };
}
export default function ProductPage() {
const { product } = useLoaderData();
return (
{product.title}
{product.description}
);
}
const PRODUCT_QUERY = `#graphql
query Product($handle: String!) {
product(handle: $handle) {
id
title
description
handle
variants(first: 1) {
nodes {
id
price {
amount
currencyCode
}
}
}
featuredImage {
url
altText
}
}
}
`;
Hydrogen Components
import {
Image,
Money,
CartForm,
CartLineQuantity,
useCart,
} from '@shopify/hydrogen';
// Image Component
// Money Component
// Add to Cart
Add to Cart
Cart Management
// app/routes/cart.tsx
import { CartForm } from "@shopify/hydrogen";
import { type ActionFunctionArgs } from "@remix-run/cloudflare";
export async function action({ request, context }: ActionFunctionArgs) {
const { cart } = context;
const formData = await request.formData();
const { action, inputs } = CartForm.getFormInput(formData);
switch (action) {
case CartForm.ACTIONS.LinesAdd:
return await cart.addLines(inputs.lines);
case CartForm.ACTIONS.LinesUpdate:
return await cart.updateLines(inputs.lines);
case CartForm.ACTIONS.LinesRemove:
return await cart.removeLines(inputs.lineIds);
default:
throw new Error("Unknown cart action");
}
}
export default function CartPage() {
const cart = useLoaderData();
return (
{cart.lines.nodes.map((line) => (
))}
);
}
Collections
// app/routes/collections.$handle.tsx
export async function loader({ params, context }: LoaderFunctionArgs) {
const { handle } = params;
const { storefront } = context;
const { collection } = await storefront.query(COLLECTION_QUERY, {
variables: { handle, first: 24 },
});
return { collection };
}
const COLLECTION_QUERY = `#graphql
query Collection($handle: String!, $first: Int!) {
collection(handle: $handle) {
id
title
description
products(first: $first) {
nodes {
id
title
handle
featuredImage {
url
altText
}
priceRange {
minVariantPrice {
amount
currencyCode
}
}
}
}
}
}
`;
Advanced Patterns
Search Implementation
// app/routes/search.tsx
export async function loader({ request, context }: LoaderFunctionArgs) {
const url = new URL(request.url);
const searchTerm = url.searchParams.get("q");
if (!searchTerm) {
return { results: null };
}
const { storefront } = context;
const { products } = await storefront.query(SEARCH_QUERY, {
variables: { query: searchTerm, first: 20 },
});
return { results: products };
}
const SEARCH_QUERY = `#graphql
query Search($query: String!, $first: Int!) {
products(query: $query, first: $first) {
nodes {
id
title
handle
featuredImage {
url
altText
}
}
}
}
`;
Customer Authentication
// app/routes/account.login.tsx
export async function action({ request, context }: ActionFunctionArgs) {
const { customerAccount } = context;
const formData = await request.formData();
const email = formData.get("email");
const password = formData.get("password");
const { customerAccessTokenCreate } = await customerAccount.mutate(
LOGIN_MUTATION,
{ variables: { input: { email, password } } },
);
if (customerAccessTokenCreate.customerAccessToken) {
// Store token in session
return redirect("/account");
}
return { errors: customerAccessTokenCreate.customerUserErrors };
}
Localization
// Multi-currency and language support
export async function loader({ request, context }: LoaderFunctionArgs) {
const { storefront } = context;
// Get localized data
const { localization } = await storefront.query(LOCALIZATION_QUERY);
// Query with localization context
const { product } = await storefront.query(PRODUCT_QUERY, {
variables: { handle, country: "CA", language: "FR" },
});
return { product, localization };
}
Oxygen Deployment
Deploy from CLI
# Link to Shopify store
npx shopify hydrogen link
# Deploy to Oxygen
npx shopify hydrogen deploy
Environment Variables
Set environment variables in Shopify admin:
- Go to Sales channels > Hydrogen
- Select your storefront
- Add environment variables
Preview Deployments
Every git push creates a preview URL for testing.
# Push to create preview
git push origin feature-branch
Bring Your Own Stack
If not using Hydrogen, you can use the Storefront API with any framework:
Install Headless Channel
# In your Shopify admin, install the Headless channel
# Create a storefront and get API credentials
Use with Next.js
// lib/shopify.ts
const domain = process.env.SHOPIFY_STORE_DOMAIN;
const storefrontAccessToken = process.env.SHOPIFY_STOREFRONT_ACCESS_TOKEN;
export async function shopifyFetch({ query, variables }) {
const endpoint = `https://${domain}/api/2025-01/graphql.json`;
const response = await fetch(endpoint, {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-Shopify-Storefront-Access-Token": storefrontAccessToken,
},
body: JSON.stringify({ query, variables }),
});
return response.json();
}
Storefront Web Components
Performance Best Practices
- Server-side rendering - SSR for initial page load
- Streaming - Use React Suspense for progressive loading
- Image optimization - Use Hydrogen's Image component
- Code splitting - Lazy load non-critical components
- Cache headers - Configure appropriate cache policies
- Prefetching - Prefetch links on hover
// Streaming example
import { Suspense } from "react";
function ProductPage() {
return (
}>
);
}
CLI Commands Reference
| Command | Description | | ------------------------------ | ------------------------ | | npm create @shopify/hydrogen | Create new project | | npm run dev | Start dev server | | npm run build | Build for production | | npx shopify hydrogen link | Link to store | | npx shopify hydrogen deploy | Deploy to Oxygen | | npx shopify hydrogen preview | Preview production build |
Resources
- Hydrogen Documentation
- Storefront API Reference
- Hydrogen Components
- Oxygen Hosting
- Demo Store Template
For API details, see the [api-graphql](../api-graphql/SKILL.md) skill.
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: dragnoir
- Source: dragnoir/Shopify-agent-skills
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.