---
description: Hydrogen storefront conventions
globs: ["app/**/*.{ts,tsx}", "server.ts", "*.graphql"]
alwaysApply: false
---

# Shopify Hydrogen

## Commands
`npm run dev` (Hydrogen dev server with Mini Oxygen) · `npm run build` · `npm run codegen` (Storefront API types) · `npm run typecheck` · `npm run lint`. Deploys go through Oxygen/CI; never run a production deploy unless asked.

## Data
- Load data in route `loader`s with `context.storefront.query(QUERY, { variables, cache })`. Never call the Storefront API from components or with a hand-built `fetch`.
- Queries are `#graphql`-tagged template strings with reusable fragments; request only fields the route renders. Run codegen after changing a query and use the generated types.
- Pass `country` and `language` from `context.storefront.i18n` via `@inContext` for localized prices.
- Pick a cache strategy on every query: `CacheLong()` for menus/shop data, `CacheShort()` for products/collections, `CacheNone()` for customer or cart data.
- Split critical vs deferred data: await what's above the fold; return non-critical promises and render them with `<Suspense>`/`<Await>`.
- Customer data uses the Customer Account API client from context, never the Storefront token; it is never cached publicly.

## Cart and UI
- Cart mutations go through the cart handler in actions (`context.cart.addLines`, `updateLines`, `removeLines`) with `CartForm`. Optimistic UI is fine; the server response is the source of truth.
- Use Hydrogen components (`Image`, `Money`, `Pagination`/`getPaginationVariables`) instead of reimplementing them.
- Handle missing products with `throw new Response('Not found', { status: 404 })`.

## SEO and performance
Set route `meta` from product/collection SEO fields; keep canonical URLs and structured data. Use `Image` with `sizes`, avoid client-only fetching for anything indexable, and check the Storefront API version in `server.ts` before using newer fields.
