Forward is a fresh Next.js App Router storefront theme for Shopify, powered by Weaverse.
Forward always runs against a real Shopify store. Products, collections,
pages, articles, policies and the main-menu / footer menus are read from
the Storefront API with the server-only credentials; the cart is the Shopify
Cart API. Without a complete Shopify environment the app refuses to start.
Theme copy comes from Weaverse theme settings. Locale/market routing remains
deferred.
Requires Bun (package manager and script runner) and Node.js >= 22.18.0 (the route tooling executes TypeScript directly with Node's built-in type stripping; the app itself stays Node-compatible — Bun is a tooling decision, not a production runtime).
bun install
bun run devOpen http://localhost:3333. The development script
uses port 3333 by default.
The Hydrogen baseline was initialized in this existing Next.js app with:
npx @shopify/hydrogen@preview setupThat deterministic command installs the preview package and copies Shopify's
Hydrogen implementation skills into .agents/skills/. The server-owned
Storefront read client is wired; cart mutations, request-specific buyer
context, checkout, and Customer Account remain explicit future work.
| Command | What it does |
|---|---|
bun run dev |
Start the development server on http://localhost:3333. |
bun run build |
Create the production build. |
bun run start |
Serve the production build. |
bun run typecheck |
Strict TypeScript check (tsc --noEmit). |
bun run lint |
Biome lint (biome lint .). |
bun run format |
Format the repository and sort imports with Biome (writes). |
bun run format:check |
Verify formatting and import order without writing. |
bun run test |
Unit and DOM tests via Bun's test runner; they use the test fixtures in tests/fixtures/, never a network. |
bun run check:routes |
Verify the route contract against actual build output (.next manifests). Requires a prior bun run build. |
bun run smoke:routes |
Start the production server, verify every contract path and redirect over HTTP, then stop the server. Requires a prior bun run build. |
bun run check |
Composed gates: typecheck → lint → format:check → test → check:graphql → build → check:theme → check:routes. The build needs the Shopify environment. Leaves no server running. |
Storefront data flows through a single replaceable seam:
server-only Shopify Storefront API reads
-> ShopifyCatalogDataSource
-> normalized storefront view models (src/lib/storefront/types.ts)
-> route loaders / page composition (src/app/**)
-> visual components (src/components/**)
Pages and components never read Shopify directly — everything goes through
the exported storefront instance. Unknown dynamic handles resolve to null
and routes answer with real notFound() 404s. Fixtures under
tests/fixtures/storefront/ are test data only.
The cart is the server-owned Shopify Cart API; checkout is handed off to Shopify.
The single source of truth is src/lib/routes/route-contract.ts. Shell UI, next.config.ts redirects, the build checker, the HTTP smoke, and the tests all read from it.
Every rendered route lives under src/app/[locale]/, with markets listed in src/lib/i18n/locales.ts. The default market (en-us) is never in the URL: the proxy redirects /en-us/shop to /shop (308) and rewrites /shop to /en-us/shop internally. Other markets keep their prefix (/de-de/shop); an unknown prefix is a 404. The routes below are the default-market paths.
| Route | Surface |
|---|---|
/ |
Home |
/shop |
Full catalog |
/shop/[collectionHandle] |
Collection |
/products/[productHandle] |
Product |
/search |
Search |
/cart |
Cart |
/journal |
Journal index |
/journal/[articleHandle] |
Journal article |
/pages/[pageHandle] |
Store page |
/policies/[policyHandle] |
Store policy |
/account |
Account overview |
/account/orders |
Order history |
/account/orders/[orderId] |
Order detail |
/account/addresses |
Addresses |
/account/login |
Sign in |
/account/authorize and /account/logout are explicit placeholders that answer 501 Not Implemented. These handlers do not pretend otherwise. Account records come only from the Customer Account API; a deployment without account configuration renders no account data.
/robots.txt and /sitemap.xml are generated by App Router metadata routes against a placeholder origin (https://forward.example); the production domain is a deferred deployment decision.
| From | To |
|---|---|
/collections/all |
/shop |
/collections/[collectionHandle] |
/shop/[collectionHandle] |
/blogs/journal |
/journal |
/blogs/journal/[articleHandle] |
/journal/[articleHandle] |
Dynamic routes are smoke-tested with approved handles only
(weatherline-shell, ridge-30-field-pack, talus-trail-shoe for products,
plus one handle per other resource class). They live in
src/lib/routes/route-contract.ts and resolve against the live store;
unknown handles return real 404s.
Shopify's shopify hydrogen check routes inspects the file-based routes of Shopify's React Router Hydrogen skeleton. Forward uses the Hydrogen preview package inside Next.js App Router, so that framework-specific route checker is not authoritative here. The equivalent is bun run check:routes, which validates generated App Router manifests in .next/ (not source filenames) against this repo's own route contract, plus bun run smoke:routes, which verifies live HTTP behavior — including permanent redirects — against a production server.
- No locale/market routing (markets are TBD in the shared contract).
- Vercel Production deployment is configured separately from repository data adapters; credentials remain outside Git and browser bundles.