Development example for exercising Hydrogen APIs in Astro. This is not a starter template. See
../README.mdfor context.
Port of the canonical examples/core design to Astro running on the Node SSR adapter.
- Astro's
.astrocomponent model — frontmatter (---) for server-side data fetching, template body for markup. - File-based routing under
src/pages/(index.astro,collections/[handle].astro,products/[handle].astro,blogs/news/[handle].astro). - On-demand SSR via
@astrojs/node(output: "server"), matching the data path of the React Router and Next.js examples. - Colocated GraphQL queries (each page owns its query and types in its frontmatter).
- Shared chrome (
Header,Footer) lives insrc/layouts/BaseLayout.astro, not per-page. - Tailwind v4 via
@tailwindcss/vite— the design's@themetokens live insrc/styles/global.css.
| Route | Source | Status |
|---|---|---|
/ |
examples/core/reference/home.html |
Live: hero is static; featured products grid pulls from products(first: 3) |
/collections |
examples/core/reference/collections.html |
Live: queries collections(first: 12) |
/collections/:handle |
examples/core/reference/collection.html |
Live: queries collection(handle:) with up to 24 products |
/products/:handle |
examples/core/reference/product.html |
Live: gallery, options (Size + Color swatches), add-to-cart UI; "You may also like" pulls from products(first: 4) |
/blogs/news |
(new) | Live: first article rendered as featured, rest in a 2-col grid |
/blogs/news/:handle |
(new) | Live: article body comes back as contentHtml and is rendered with set:html |
/account |
(new) | Live: Customer Account OAuth session, basic customer name/email, logout form |
/account/login |
(new) | Live: Hydrogen Customer Account handler starts OAuth and stores pending PKCE state |
POST /account/logout |
(new) | Live: Hydrogen Customer Account handler clears session and redirects with 303 See Other |
- Live: product data, collection data, prices, images, options, news articles, article body HTML, Customer Account login/session state, basic customer identity, logout.
- Stubbed: hero links, cart count badge, search, add-to-cart button (no cart mutation), newsletter form, color swatch hex values (mapped server-side from option name → CSS color in
src/pages/products/[handle].astro).
The account flow uses createCustomerSession and createCustomerAccountServerHandlers from @shopify/hydrogen/customer-account, Customer Account values from examples/shared/config.ts, and an encrypted HttpOnly __Host- cookie adapter from examples/shared/customer-session.ts.
Customer Account OAuth requires a public HTTPS origin. To test locally without a tunnel, run:
pnpm --filter @shopify/hydrogen-example-astro dev:httpsThe local HTTPS plugin provisions the certificate, links an unlinked Hydrogen storefront, and pushes the Customer Account callback, JavaScript origin, and logout URLs. If automatic setup is unavailable, it prints the values for manual configuration.
# from the repo root
pnpm install
pnpm --filter @shopify/hydrogen-example-astro devThen open http://localhost:4321.
To build and serve the production output:
pnpm --filter @shopify/hydrogen-example-astro build
pnpm --filter @shopify/hydrogen-example-astro startpnpm start runs the standalone Node server emitted by @astrojs/node (node ./dist/server/entry.mjs) and listens on port 4321 by default.
storefrontClient.graphql()fromAstro.locals.storefrontClient— uses the request-scoped client created insrc/middleware.tswith typed query support viagql(). Types are inferred directly from query strings against the Storefront API schema — no manual type definitions or casts needed. Error normalization and request-id propagation are handled by the core client.formatMoney()insrc/lib/money.ts— every example needs money formatting from aMoneyV2-shaped object.ProductCard.astroreads a narrow product shape (handle,title,featuredImage,priceRange.minVariantPrice). A core fragment + type for "product card" would let routes share GraphQL fragments instead of re-listing fields.- Color swatch mapping (
SWATCHESinsrc/pages/products/[handle].astro) is hand-rolled — option-value → swatch metadata is a real merchant problem; the SDK should have an opinion on how to expose it.
- Astro is server-by-default in this example, but its sweet spot is static + islands. Worth a sibling experiment that flips
output: "static"and usesgetStaticPathsto pre-render collections/products at build time, then layers an interactive Add-to-Cart island on top — that would exercise Astro's actual differentiator versus the React Router / Next.js ports. - No type-aware
Astro.params. The[handle]segment is typed asstring | undefinedin the frontmatter — a thin codegen (astro syncalready runs for content collections; could it also typegen route params?) would close the gap with React Router'sRoute.LoaderArgsand Next.js's typedparamspromise. @astrojs/nodemajor needs to trackastromajor. I initially picked^9.5.4, which silently installed alongsideastro@6and broke the production build with a missingapplyPolyfillsexport — pnpm only logs the peer-dep mismatch, doesn't fail. The skill should call out that the Node adapter major number tracks Astro's (Astro 5 → adapter 9, Astro 6 → adapter 10).