The storefront behind shop.remix.run.
The storefront runs on Remix 3 and framework-neutral Hydrogen across native Node/Fly and Oxygen runtimes.
- Node.js 24
- pnpm 10.33.4
pnpm install
cp .env.example .env
# Populate PRIVATE_STOREFRONT_API_TOKEN from the configured Hydrogen environment.
pnpm devThe private Storefront token remains server-only and enables request-aware cart,
checkout, and Shopify redirect handling. Oxygen supplies oxygen-buyer-ip; Fly
supplies fly-client-ip, or behind Fastly, x-cdn-client-ip authenticated by
CDN_ORIGIN_SECRET (see FLY_DEPLOYMENT.md). Other Node runtimes use the client address resolved by
Remix's HTTP adapter from the socket or, when explicitly configured behind a
trusted proxy with TRUST_PROXY=true, overwritten proxy headers. Never forward
platform buyer-IP headers outside their runtime. PUBLIC_CHECKOUT_DOMAIN is not
a runtime input; checkout uses Shopify's
authoritative cart.checkoutUrl. The app does not use durable application
sessions or require SESSION_SECRET.
pnpm dev runs the framework-native Node server with remix/assets. For UI-heavy work, use pnpm hmr to preserve browser state while hot-updating client and server modules. Use pnpm dev:oxygen when testing the same application under MiniOxygen's Worker runtime.
The example environment points at the live production store. Purchases create real orders and charge real money.
pnpm lint
pnpm typecheck
pnpm test
pnpm test:e2e
pnpm test:e2e:oxygen:dev
pnpm test:e2e:oxygen
pnpm build:oxygen
pnpm preview:oxygenThe end-to-end suites use a deterministic local Storefront fixture: test:e2e runs native Node, test:e2e:oxygen:dev runs MiniOxygen development, and test:e2e:oxygen builds and runs the production Worker. Pull requests exercise all three runtimes. Set BASE_URL to target an existing deployment instead.
The Oxygen build produces a self-contained Worker at dist/server/index.js and browser assets in dist/client/. MiniOxygen preview and Shopify CLI discover these standard output directories automatically. The Node server compiles browser modules through remix/assets for Fly.
| URL | What it is |
|---|---|
| remix-store.freetls.fastly.net | Use this one. Fly app behind the Fastly CDN |
| remix-store.fly.dev | Fly origin, bypasses the CDN (debugging, health checks) |
Fastly caches fingerprinted /assets/* files and short-lived root public/
files; HTML is private, no-store and always reaches Fly. Responses served
through Fastly include X-Cache and X-Served-By headers.
Oxygen deployments use .github/workflows/oxygen-deployment.yml; pnpm deploy:oxygen deploys a preview locally. Both pass --build-command 'pnpm build:oxygen' so Shopify CLI runs this app's Vite build. The build writes the pinned compatibility date to dist/server/oxygen.json alongside the Worker.
Fly setup, secrets, local image verification, and continuous deployment are documented in FLY_DEPLOYMENT.md.
app/routes.tsdefines the typed route contract.app/router.tsowns the shared Fetch app, routes, middleware, and runtime boundary.app/assets.tsdefines the shared metadata contract, document asset sources, and document asset factory.app/assets.node.tsconstructs the native Remix asset server;app/assets.oxygen.tsconstructs Pitlane's Worker-safe manifest resolver.app/node.tscomposes Node static files, Remix Assets, rendering, and routing.app/middleware/storefront.tscreates a request-scoped Hydrogen Storefront client.app/middleware/render.tsxcontains runtime-neutral streaming SSR.app/runtime.tsbinds environment, cache, andwaitUntilvalues to each request.server.node.tsowns the Node/Fly-compatible HTTP lifecycle.app/entry.oxygen.tscomposes and serves the Oxygen Worker runtime.app/actions/public/entry.tsxhydrates browser components on both targets.vite/remix-oxygen.tscomposes Pitlane's Remix Vite plugin with MiniOxygen, then bundles Pitlane's asset manifest into the singleindex.jsWorker that Oxygen deploys. Deploy builds serve assets from the deployment's CDN prefix (HYDROGEN_ASSET_BASE_URL), so they stay reachable after later deployments.
Pitlane's resolver implements the metadata interface consumed by Remix's render({ assets }) middleware. Remix owns streaming, frames, and hydration; Pitlane rewrites clientEntry(import.meta.url, ...) to portable file:app/…#Export identities and resolves them to built browser modules. The installed Remix asset server compiles from the filesystem in Node, so Oxygen needs this build-time bridge. browserBoundary in app/assets.ts defines which sources are public: the Node asset server refuses to serve anything outside it, and the Oxygen build and dev server fail when a browser module imports something outside it.
MIT License — see LICENSE.md.