Quick start
This page builds the smallest complete storefront: one server-only client, a home page that lists the store's products, and a product page that answers a real 404. Every file is shown in full; together they type-check and build for Cloudflare and for Vercel.
What you need
Node 22.12 or newer, the store's API origin (COD_SERVER_URL) and a store API
key (STORE_API_KEY). A self-hosted Wocart runs its API locally on
http://localhost:8787.
1. Create the project
Code
zod 4 is the SDK's peer dependency. A Wocart storefront runs on two hosts
from the same code, Cloudflare Workers and Vercel, so it installs both
adapters; wrangler runs the Cloudflare build locally. Then set the build
scripts in package.json:
Code
build is the Cloudflare build (dist/), build:vercel the Vercel build
(.vercel/output).
2. Configure Astro
astro.config.mjs
Both values are server secrets: never PUBLIC_*, never rendered into a
page, never passed to a browser script. They are optional so a build never
needs a store; a request without them fails loudly instead (step 3).
DEPLOY_TARGET=vercel builds with the Vercel adapter; without it the
storefront builds for Cloudflare. session: false keeps the Cloudflare Worker
from requiring a SESSION KV namespace the storefront never uses. Images pass
through: Astro's default
sharp service would put native binaries for the build machine into the
Vercel output. To resize store images on either host, use the
media image service.
The Cloudflare build reads its runtime from wrangler.jsonc:
wrangler.jsonc
astro dev runs in Cloudflare's local runtime, which reads its values from
.dev.vars:
.dev.vars
Never commit it: add .dev.vars, .wrangler/ and .vercel/ to
.gitignore.
3. One module creates the client
src/lib/store.ts
- One place. If the origin or key is wrong, this is the file to inspect. No page builds its own client.
- A new client per call, so per request: one request's reads never wait on another's, and a client's caches never cross requests.
createStoreClientthrowsMISSING_CONFIGURATIONwhenserverUrlorapiKeyis empty — a loud setup error instead of a store that silently looks empty.onErroris the only place you see why a read degraded: reads never throw (step 5).localeasks the server for a published language other than the primary. Store config and languages adds language routing.
4. List the products
src/pages/index.astro
config.get()andproducts.list()run in parallel: neither needs the other.- Empty is a state, not an error. A failed read and a store with no
products both give
[]. Design the empty page;onErrortells you which. storefrontPath("product", { handle })gives/products/<handle>, the platform's path for a product. Never write the string by hand.formatMoneyplaces the store's currency symbol for its language.
5. Render a product
src/pages/products/[handle].astro
src/pages/404.astro
- The handle is the product's public address. Never look a product up by its internal id in a URL.
nullis a real 404.notFound(Astro)renders your/404page with status 404 and turns caching off for that response, so a product published a minute later is not hidden by a cached refusal.- A description is either text or HTML (
descriptionFormat). HTML was sanitized by the server when the merchant saved it: render it withset:html, and never sanitize it again or print it as text. Text is always escaped.
6. Run it
Code
Open http://localhost:4321: the store's name and products, each linking to
its page. /products/nope answers 404.
Where next
| Next | Page |
|---|---|
| Serve every published language at its own URL | Store config and languages |
| Add the order form and the same-origin API routes | Astro actions and routes, Checkout and OTP |
| Add a basket | Basket and quotes |
| Show delivery prices per wilaya | Delivery and geography |
| Let merchants edit the design in Wocart Studio | The theme starter |
The browser never gets the key
Browser scripts import only @wocart/storefront (its root entry) and
@wocart/storefront/review-media. Anything that needs the store goes through a
route of your own that calls the SDK on the server —
createStorefrontRoutes builds them for you.