Docs
Dashboard
View as Markdown
On this page
  1. Set up
  2. Environment
  3. How it fits together
  4. Pages that refresh when you save
  5. Checkout
  6. Deploy

Next.js starter

A complete headless store on the Next.js App Router: server components, a cart, checkout, buyer accounts and pages that refresh when you save.

A complete store on the Next.js App Router, running on your ShopFast store through the Storefront API and the SDK. Server components fetch the catalog, server actions run the cart and sign-in, and your store’s own checkout takes the payment. Deploy it as it is, or make it yours. The code is on GitHub (MIT).

Page What it does
Home The store’s hero, collections, categories and featured products
Product Gallery, options, live stock, reviews, recommendations, add to cart, Product JSON-LD
Collection, category Sorting and “Show more” with cursor pagination
Search Suggestions as you type, results with type filters and sorting
Cart Quantities, discount codes and gift cards in one field
Checkout Its own checkout page (your ways to pay, fields, questions, terms, tips and email codes), or the embedded or hosted checkout
Account Sign-in with an emailed code, orders, license keys and downloads, wallet, subscriptions, tickets
Order The receipt link (/orders/<id>?access=…) with keys and downloads once paid
Policies, support Your policy pages and a support form

It also has a sitemap, robots, and a loading.tsx on every route drawn from that page’s own layout, so nothing moves when the page arrives.

Set up

  1. Get the code and install it:

    npx degit anurag12340/shopfast-next-storefront my-store
    cd my-store
    npm install
  2. In Settings → Headless & MCP → Storefront keys, create a private key (sfsk_…). The starter calls the API from its server only, so the key never reaches a browser.

  3. Copy .env.example to .env.local and fill it in (see Environment).

  4. Run it:

    npm run dev       # http://localhost:3000
  5. In Settings → Developers → Webhooks, add an endpoint at https://<your site>/api/revalidate for the storefront.updated event and put its signing secret in SHOPFAST_WEBHOOK_SECRET. Pages then update seconds after you save a product; without it they refresh every 5 minutes.

  6. Add your site’s origin (https://shop.example.com, and http://localhost:3000 while you develop) to the storefront key’s allowed origins. Checkout sends buyers back only to a site listed there, and the embedded checkout opens only there.

Environment

Variable
SHOPFAST_SHOP Your store’s handle (the part before .shopfa.st) or its st_ id
SHOPFAST_STOREFRONT_KEY The private storefront key (sfsk_live_…). Server only
SHOPFAST_WEBHOOK_SECRET The signing secret of your storefront.updated endpoint (whsec_…)
SITE_URL Where the site is served, for canonical links, Open Graph, the sitemap and the checkout’s return pages
SHOPFAST_CHECKOUT custom (the default: the site’s own checkout page), embedded or hosted
SHOPFAST_API_URL Leave it out: https://api.shopfa.st

How it fits together

lib/shopfast.ts makes two clients. The catalog client is shared by every buyer and keeps its answers in Next’s Data Cache with tags; the buyer client carries this buyer’s address and session and is never cached:

import { createNextStorefrontClient } from '@shopfast-sdk/client/next';

export function catalog() {
  return createNextStorefrontClient({ shop: config.shop, key: config.key, revalidate: 300 });
}

export const buyer = cache(async () => {
  const [h, c] = await Promise.all([headers(), cookies()]);
  return catalog().with({ buyerIp: buyerIp(h), customerToken: c.get('sf_customer')?.value ?? null });
});
File What it does
lib/shopfast.ts The two clients, and the cached reads every page shares
app/actions/*.ts Server actions: the cart, sign-in, support, live stock and search suggestions
components/BuyBox.tsx Options, quantity, add to cart and the live stock line
components/EmbeddedCheckout.tsx Your store’s checkout in an overlay on this site
app/api/revalidate/route.ts The storefront.updated webhook

The cart id and the buyer’s session token live in httpOnly cookies. Writes go out from server actions, so a buyer never talks to the API directly and your private key stays on the server.

Pages that refresh when you save

Every cached answer carries the tag shopfast:<shop>, and product, collection and page answers carry their own (shopfast:<shop>:product:<handle>…). When you change something, ShopFast sends storefront.updated and the route refreshes exactly those tags:

// app/api/revalidate/route.ts
import { revalidateTag } from 'next/cache';
import { handleRevalidationWebhook } from '@shopfast-sdk/client/next';

export function POST(request: Request) {
  return handleRevalidationWebhook(request, { secret: process.env.SHOPFAST_WEBHOOK_SECRET!, revalidateTag, shop: process.env.SHOPFAST_SHOP! });
}

Checkout

SHOPFAST_CHECKOUT picks one of the three ways in Headless checkout:

  • custom: /checkout is the site’s own page, drawn from cart.checkoutOptions. It starts the checkout with cart.checkout, asks for the emailed code when the store wants one, and sends the buyer to payUrl. After paying, the buyer comes back to /checkout/complete, which keeps the order’s access token in a cookie and opens the order.
  • embedded: your store’s checkout in an overlay on the cart page, opened with the same cart (embed.cart).
  • hosted: a signed link to your store’s checkout, back to the site after paying.

Payment methods, taxes, fraud checks and delivery are your store’s own in all three.

Deploy

Any host that runs Next.js works (Vercel, Netlify, a Node server). Set the variables above, then npm run build. The buyer’s address is read from the first x-forwarded-for hop, which is what Vercel and most proxies send; on your own server, make sure your proxy sets it.

Was this page helpful?