This page assumes a project already exists on disk. To get one, export a storefront or run
shoppex storefront pull. See Code storefronts and the Theme CLI.Import and export
Move a project in and out of Shoppex as a ZIP package.
Theme CLI
Pull, push, build, and deploy from the command line.
Project structure
Every official template shares this shape. File names insidecommerce/ and config/ can differ between templates, but the folders and their purpose stay the same.
The commerce layer
src/commerce/ is where a storefront talks to Shoppex. It is not an npm package. Open package.json and no @shoppexio/* dependency appears there. index.html instead loads the Storefront SDK as a script, pinned to a version channel:
window.shoppex. src/commerce/shoppex.ts wraps that global with two functions:
getShoppex() also runs the SDK’s one-time setup. It uses bootstrap globals a Shoppex worker injects next to the product catalog: shopSlug, shopId, apiBaseUrl, defaultCurrency, and an optional checkoutBaseUrl. A storefront without these globals cannot price a cart or check out, so getShoppex() fails fast instead of rendering with broken commerce.
The catalog and the merchant’s content arrive the same way, read by src/config/site-config.ts:
Neither function makes a network request. Both read
window.__SHOPPEX_INITIAL__, injected by the same worker before the page renders.
For cart and checkout, use the useCart hook from src/commerce/cart.tsx instead of calling the SDK directly. A component under CartProvider gets cart state and the actions that keep it, the SDK, and the current price quote in agreement:
useCart() returns lines, count, quote, and the actions add, update, remove, clear, applyCoupon, removeCoupon, and checkout. checkout calls the SDK’s checkout() and returns { success, message, code, redirectUrl, invoiceId }.
If a product has required checkout fields, collect them before calling
checkout. resolveCheckoutFields(lines, products) and checkoutNeedsDetails(fields) in checkout-fields.ts tell you when a form must run first, and what to write onto the cart lines.src/commerce/sdk.d.ts types the full window.shoppex surface this project uses. The complete method and type reference for the SDK lives at Storefront SDK reference.
Editable content: content-defaults.json
src/config/content-defaults.json is the template’s own text and settings: brand name, navigation links, hero copy, theme colors, cart labels, and the content for each page section. getSiteConfig() reads this file and merges the merchant’s saved content over it. The merge is a partial override: objects merge field by field, and arrays and single values replace completely.
src/config/content-schema.json describes the field types in content-defaults.json. The Design tab then renders a color picker, a select, or a number field instead of raw text, for every value it can.
Without
content-defaults.json, the Design tab has no fields to show. The storefront still works. Content edits then happen in Code or with AI instead of the Design tab.Working locally
Every template runs on the same two commands.bun run dev on its own renders no storefront. Every route shows a configuration error instead, because the store record and the SDK bootstrap globals have no local substitute. The values the app needs are these:
See it running with real data
Templates ship no local mock for these values on purpose, so a half-built shop never looks like a working one. Two paths reach real data:- Push and preview. Run
shoppex storefront pushto send your local project, then open the storefront under Store → Storefronts. This path needs no stub and matches production exactly. - Write your own stub. Serve a build with a static server, drop the
cdn.shoppex.ioscript tag, and inject the globals above before the app runs. Keep the stub out of version control. Give every global a real value, not an empty string, and keep its synchronous methods, as typed insdk.d.ts, returning values instead of promises.
What the build expects
Every code storefront builds the same way:- A
buildscript inpackage.json - No network access while the script runs
- Output in
dist,out, orbuild, with anindex.htmlat its root