Set Up an Evolve Storefront App
Wire a new client storefront (a Next.js app) as a thin consumer of the
@evolve-storefront frontend packages: logic and primitives stay npm
dependencies, the app owns only composition, brand, and page markup.
When to Use
Section titled “When to Use”- Bootstrapping a new client storefront on top of
@evolve-storefront. - Adding an
@evolve-storefrontpackage (ui,layout,feature-*) to an existing app and wiring it correctly. - Diagnosing a component that renders subtly unstyled / broken — almost
always a missing per-package
styles.cssimport (see The one that bites). - Setting up locale message merging or a feature provider.
Read ../../evolve-storefront/AGENTS.md
alongside this — it is the authoritative consumer contract. This skill is the
step-by-step; that file is the why.
The layered model (what the app is responsible for)
Section titled “The layered model (what the app is responsible for)”| Layer | What | Lives where |
|---|---|---|
| 1 | Headless logic | @evolve-storefront/feature-* (npm) |
| 2 | Presentational primitives | @evolve-storefront/ui (npm) |
| 3 | Composition / page markup + brand | your app |
The app is Layer 3 and must stay thin. Any business rule belongs in a Layer-1
hook — if it could have a bug, it does not belong in composition markup. ui
is domain-agnostic and prop-driven; never add data fetching there.
Prerequisites
Section titled “Prerequisites”- Node.js >= 24.8 (
.nvmrc), pnpm >= 11 via Corepack — runcorepack enable. - A Next.js app (App Router) with Tailwind CSS v4 (CSS-first — no
tailwind.config.*). If starting fresh,pnpm create next-appthen migrate styling to Tailwind v4. - Access to the
@evolve-storefront/*packages (workspace, or the private npm registry the org publishes to).
1. Add the packages
Section titled “1. Add the packages”Depend only on what you use. Typical starting set:
// package.json (versions: match the registry; workspace:* inside evolve-platform){ "dependencies": { "@evolve-storefront/ui": "^0.2.0", "@evolve-storefront/layout": "^0.2.0", "@evolve-storefront/feature-shopping-list": "^0.2.0", "next-intl": "^3", "react": "^19", "react-dom": "^19", "tailwindcss": "^4" }}Feature packages pull their own deps (@evolve-storefront/core, errors, ui)
transitively — you do not list those unless you import them directly.
2. Wire the brand + every package’s styles.css (the critical step)
Section titled “2. Wire the brand + every package’s styles.css (the critical step)”Tailwind v4 only generates the classes it can find in scanned sources. Each
Evolve package ships a tiny styles.css that registers its own source dir
with a package-local @source, exposed at the ./styles.css export. Your app’s
global stylesheet must @import one for every package it consumes:
/* app/globals.css (or src/app/globals.css) */
/* 1. Your brand: the Tailwind entry (@import "tailwindcss"), your @theme tokens, and the base layer. Start from evolve-storefront packages/ui/global.css and make it your own — it is the DEFAULT brand, not a package export. */@import "./brand.css";
/* 2. One line per consumed package — this is what makes their classes exist. */@import "@evolve-storefront/ui/styles.css";@import "@evolve-storefront/layout/styles.css";@import "@evolve-storefront/feature-shopping-list/styles.css";Use CSS @import (one Tailwind compilation unit), not
@source "@evolve-storefront/<pkg>" — the latter works but hardcodes the
package’s internal layout into your app and breaks when the package moves its
sources.
Brand contract. Your brand @theme must define the color/radius/font tokens
and the page-shell tokens --container-max, --container-padding,
--container-padding-lg — ui’s Container reads them, so content width is a
token change, not a component change.
Text is semantic HTML. There is no Text/Display component. Style
<p>/<small> and the h1–h6 rules in your brand’s @layer base; use
Heading only to map a level to a tag (it emits no classes).
The one that bites: per-package styles.css
Section titled “The one that bites: per-package styles.css”Forgetting a package’s @import fails silently — no error, no warning. The
component renders with its structure but none of its utility classes, so it
looks like a bug in the component rather than a missing stylesheet. It recurs
every time you adopt another package, because the app already worked before.
If an
@evolve-storefrontcomponent looks subtly wrong, checkglobals.cssfor itsstyles.cssimport first, before touching the component.
3. Merge locale messages (next-intl)
Section titled “3. Merge locale messages (next-intl)”Every package that ships strings ships all five locales — en (US), nl,
de, fr, es — under its ./messages/* export (e.g.
@evolve-storefront/feature-shopping-list/messages/en.json). en is the
source and the only guaranteed-complete locale. Merge each consumed package’s
file for the active locale in your next-intl request config, then let app
messages win last:
// i18n/request.ts (sketch)import deepmerge from "deepmerge";
async function load(locale: string) { const [ui, layout, shoppingList, app] = await Promise.all([ import(`@evolve-storefront/layout/messages/${locale}.json`), import(`@evolve-storefront/feature-shopping-list/messages/${locale}.json`), import(`./messages/${locale}.json`), ]); // app messages last so a brand can override any package string. return deepmerge.all([layout.default, shoppingList.default, app.default]);}Status keys mirror the evolve-framework GraphQL enums verbatim (e.g.
CANCELLED, Cancelled) — never normalize a key’s casing/spelling. Register is
informal by default (je/du/tu/tú); a formal brand (German B2B → Sie)
overrides the affected keys in the app’s own message files.
4. Wire a feature (provider + composition)
Section titled “4. Wire a feature (provider + composition)”Layer-1 features expose a ./provider, headless hooks (useShoppingList…),
and prebuilt islands. Mount the provider once, compose the islands in your page:
// Layer 3 — composition only. No business rules here.import { ShoppingListProvider } from "@evolve-storefront/feature-shopping-list/provider";import { ShoppingListOverview } from "@evolve-storefront/feature-shopping-list/shopping-list-overview";
export default function Page() { return ( <ShoppingListProvider> <ShoppingListOverview headingLevel={1} /> </ShoppingListProvider> );}Pass a headingLevel to any view that renders headings (page 1 / section 2 /
card 3) — a feature can’t know its own document depth.
Gated (auth-dependent) queries stay pending, never settle empty. When
branching on a gated hook, treat only isSuccess && !data as a real miss —
isLoading/bare data will 404 on a hard load while soft navigation works.
5. Overlays & icons (don’t reach for another library)
Section titled “5. Overlays & icons (don’t reach for another library)”- One overlay library:
react-aria-components. Adding a second (e.g. Radix portalled popovers) is a correctness bug, not a style choice — a foreign portal renders as a sibling of an RAC dialog and its options become unclickable inside a modal. - Icons go through the map. Render
<Icon name="…" />from@evolve-storefront/ui/icon(names describe the role, not the glyph). Never importlucide-reactin the app.
6. Verify
Section titled “6. Verify”corepack enablepnpm installpnpm tsc # or: pnpm checkpnpm dev # then click through: are the Evolve components fully styled?Styling regressions don’t fail tsc or tests — look at the rendered app.
The fastest check that every package is wired is a page that mounts one
component from each consumed package.
Checklist
Section titled “Checklist”- Node 24.8 + pnpm via corepack; Tailwind v4 (no
tailwind.config.*). -
globals.css: brand entry first, then one@import ".../styles.css"per consumed package. - Brand
@themedefines color/radius/font and--container-*tokens. -
next-intlmerges each package’smessages/<locale>.json, app last; all five locales present; status keys left verbatim. - Feature providers mounted; composition is thin (no business rules).
- Overlays are RAC only; icons via
@evolve-storefront/ui/icon. - Rendered app visually verified — not just
tsc.
References
Section titled “References”evolve-storefront/AGENTS.md— authoritative consumer contract (styling, layers, locales, icons, overlays).evolve-storefront/packages/ui/global.css— the default brand to fork.evolve-storefront/README.md— the copy-pasteable app stylesheet listing every package.

