Consider a Fluid theme first
We don’t recommend a headless storefront unless you need one. A Fluid theme gives you full control of the design, and a headless storefront gives up a lot in return:- No editing in the builder. Your teammates can’t change the storefront in Fluid’s page editor. Every change goes through a developer and your code.
- No droplets or marketplace items. Droplets and other marketplace items can’t attach to a headless storefront.
- No bots. Fluid’s bots can’t review your storefront’s SEO or make edits for you.
- You pay for hosting. Your servers and their costs are yours to run. Fluid themes are served free from a global CDN.
- No built-in agentic commerce. A headless storefront doesn’t include the agentic commerce features, such as UCP (Universal Commerce Protocol), that Fluid storefronts have from the start.
This guide covers a storefront that uses Fluid’s hosted checkout. To build
the checkout yourself as well, see Build a headless
checkout.
How it fits together
The starter splits the work between your server, the browser, and Fluid:
The app reads only the public storefront endpoints, which need no token. See Public and company endpoints.
Run it locally
You need Node.js 20.9 or later, pnpm, and your company’s Fluid subdomain:acme if your store is at acme.fluid.app.
1
Copy the starter
2
Point it at your company
Copy the example settings and set
FLUID_SHOP to your subdomain..env.local
3
Start the dev server
http://127.0.0.1:3000. You see your store’s products, content, languages, countries, and brand colors.Deploy it
The starter is a standard Next.js app, so it runs anywhere Next.js does.- Vercel. Use the Deploy button in the repository’s README, or import the repository, and set
FLUID_SHOP. Add your domain under the project’s domains. Canonical URLs and the sitemap follow the production domain. - Any Node.js host. Run
pnpm build, thenpnpm start. SetNEXT_PUBLIC_SITE_URLto the storefront’s public URL so canonical URLs and the sitemap use it.
Settings
OnlyFLUID_SHOP is required. .env.example lists every setting.
URLs and rep credit
Pages use the same URLs as a Fluid-hosted storefront, so existing links, shares, and QR codes keep working. Every page sits behind the credit segment: a rep’s username, such as/jordan-lee/products/beet-blend, or home when no rep is named, such as /home/products/beet-blend.
Links keep the shopper’s credit. A shopper who arrives on /jordan-lee/shop stays on /jordan-lee/... as they browse, and the SDK attributes the visit to that rep. Canonical URLs and the sitemap use /home/.... See Storefront URLs and the credit path.
Build your own templates
The starter has a folder undersrc/templates for each Fluid template type, such as product, enrollment_pack, medium, library, collection, category, post, and page, plus the page types such as home_page, shop_page, and cart_page. Each folder has a default.tsx and an index.ts that registers its templates.
A record picks its template by its slug:
- If the folder’s
index.tsregisters a template under the record’s slug, that template renders. - Otherwise,
defaultrenders.
src/templates/product/index.ts
default. See Slugs and URLs.
Templates are built from sections in src/sections, which are built from components in src/components, the same layering as a Fluid theme.
Languages and countries
The storefront offers the languages and countries your company has enabled in Fluid, and a picker in the header lets shoppers switch. It chooses a shopper’s locale the same way a Fluid-hosted storefront does: thelang and country query parameters, then the locale cookie, then the browser’s language and the shopper’s country, then your company’s default.
Prices, currencies, and product availability follow the country. Content follows the language. The SDK and checkout read the same cookie, so the cart and checkout stay in the shopper’s language and country. See Translate storefront resources and Country availability.
SEO
Every page gets a title, meta description, canonical URL, Open Graph and Twitter tags, andhreflang alternates, from each resource’s seo settings in Fluid. A resource Fluid marks as not indexable gets a noindex tag. Products, posts, and the site carry schema.org structured data, and the app serves /sitemap.xml and robots.txt. See SEO for storefront resources.
Cart and checkout
The starter loads the FairShare SDK on every page, the same bundle Fluid-hosted themes use. Shoppers add to the cart with Fluid’s cart drawer, and Checkout hands the cart to Fluid’s hosted checkout. To build your own cart UI, use the React hooks insrc/lib/fairshare/hooks.ts. See the FairShare SDK for every cart method.
Keep pages fresh
The app caches Fluid’s responses forFLUID_REVALIDATE_SECONDS. To refresh sooner, send a POST to /api/revalidate on your storefront with an Authorization: Bearer header carrying your REVALIDATE_SECRET. To refresh whenever something changes in Fluid, point a webhook at it.
What the public API doesn’t provide
A headless storefront sees only what the public storefront API returns. Plan for these gaps:- Page content. A page returns its title, description, image, and metafields, but not the content built in Fluid’s page editor. Build page content in a template. Metafields are a good home for copy merchants should be able to edit. See Metafields.
- Redirects. Redirects set up in Fluid Admin don’t apply. Add them to
next.config.ts. - Navigation menus. Your Fluid website navigation menus need
FLUID_COMPANY_PRIVATE_TOKEN. Without it, the starter uses the links insrc/config/site.ts. - Tag manager and analytics. Add your tags to the app’s layout yourself.
- Theme template choice. The template a merchant assigns in Fluid Admin isn’t returned, which is why templates match by slug.