Configuration Reference
All configuration files and environment variables used by the Maho Storefront.
wrangler.toml
Cloudflare Workers deployment configuration.
name = "maho-storefront"
main = "src/index.tsx"
compatibility_flags = ["nodejs_compat"]
[vars]
MAHO_API_URL = "https://your-maho-instance.com"
SYNC_SECRET = "your-secret-key"
[[kv_namespaces]]
binding = "CONTENT"
id = "your-kv-namespace-id"
[[rules]]
type = "Text"
globs = ["**/*.css", "**/*.txt"]
fallthrough = trueEnvironment Variables
| Variable | Type | Required | Description |
|---|---|---|---|
MAHO_API_URL | string | Yes | Base URL of Maho backend |
SYNC_SECRET | string | Yes | Shared secret for /sync and /cache endpoints. Fails closed — an unset or placeholder value rejects all requests. |
DEV_SECRET | string | No | Enables the dev toolbar and dev token authentication. If not set, the toolbar system is completely disabled. |
MAHO_API_BASIC_AUTH | string | No | HTTP Basic auth (user:pass) for the backend, injected server-side when proxying. |
STORES | string (JSON) | No | Array of { code, name, url, apiUrl? } defining the stores this Worker serves. |
USE_CF_IMAGE_RESIZE | string | No | "1"/"true" to emit responsive srcset via Cloudflare Image Resizing. Default off. See Responsive images — paid feature. |
Responsive images
Product images can be served as a responsive srcset (3 widths) using Cloudflare Image Resizing. It is off by default — when off, images render as a single <img src> with no transformations and no cost.
To enable:
- Set
USE_CF_IMAGE_RESIZE = "1"in the[vars]block for the target environment and redeploy (the flag is read at request time, per deployment — so you can enable it on one store and not another). - Enable Image Resizing on the Cloudflare zone (dashboard → Speed → Optimization → Image Resizing).
Cost
Cloudflare Image Resizing is a paid feature (~$0.50 per 1,000 unique transformations). The storefront limits each image to 3 widths to cap the number of unique transforms. Leave it off unless the image-bandwidth savings justify the cost for that store.
Why Cloudflare and not the Maho backend? The backend's image-resize endpoint requires HMAC-signed URLs that the edge Worker cannot generate, and the product API's
image/small_image/thumbnailroles point to the same source file — so CF Image Resizing is the only storefront-side option. A future backend change could return signed multi-width URLs as a free alternative.
KV Namespace
| Setting | Description |
|---|---|
binding | Variable name in Worker code (env.CONTENT) |
id | Cloudflare KV namespace ID |
Text Rules
The [[rules]] section tells Wrangler to import .css and .txt files as text strings rather than JavaScript modules. This is how public/styles.css and public/controllers.js.txt get embedded in the Worker.
KV Configuration Keys
In addition to cached catalog data, the CONTENT KV namespace stores configuration flags:
| KV Key | Type | Description | Docs |
|---|---|---|---|
config:password_gate | boolean | Enable/disable the password gate | Password Gate |
config:storefront_password | string | Password visitors must enter when gate is active | Password Gate |
# Enable password gate
npx wrangler kv key put --namespace-id=YOUR_KV_ID "config:password_gate" "true"
npx wrangler kv key put --namespace-id=YOUR_KV_ID "config:storefront_password" "my-secret"
# Disable password gate
npx wrangler kv key put --namespace-id=YOUR_KV_ID "config:password_gate" "false"stores.json
Maps store codes to theme and page configuration files. Each store code corresponds to a Maho store view.
{
"stores": {
"en": { "theme": "maho", "pageConfig": "page.json" },
"sv_2": { "theme": "tech", "pageConfig": "page-tech.json" },
"store_view_3": { "theme": "brew-beyond", "pageConfig": "page-brew-beyond.json" }
},
"defaultTheme": "maho",
"defaultPageConfig": "page.json"
}| Field | Type | Description |
|---|---|---|
stores | object | Store code → config mapping |
stores[code].theme | string | Theme name (maps to theme-{name}.json) |
stores[code].pageConfig | string | Page config filename |
defaultTheme | string | Fallback theme for unmapped stores |
defaultPageConfig | string | Fallback page config |
theme.json
Full design token configuration. Each store can have its own theme file (theme-tech.json, theme-brew-beyond.json) that overrides the base theme.json.
Full theme.json example (Fashion Demo - default theme)
{
"name": "Fashion Demo",
"description": "Bold fashion theme with punchy type, clean minimalism, and high contrast",
"colors": {
"primary": "#111111",
"primaryLight": "#1a1a1a",
"accent": "#ff2d87",
"accentHover": "#e6006e",
"accentLight": "#fff0f6",
"success": "#10b981",
"successBg": "#ecfdf5",
"error": "#ef4444",
"errorBg": "#fef2f2",
"sale": "#ef4444",
"outOfStock": "#9ca3af",
"text": "#111111",
"textSecondary": "#525252",
"textMuted": "#9ca3af",
"border": "#e5e5e5",
"borderLight": "#f5f5f5",
"bg": "#ffffff",
"bgSubtle": "#fafafa",
"bgMuted": "#f5f5f5",
"bgOverlay": "rgba(17, 17, 17, 0.04)",
"white": "#ffffff",
"black": "#000000",
"overlay": "rgba(15, 23, 42, 0.4)",
"overlayLight": "rgba(0, 0, 0, 0.5)"
},
"fonts": {
"sans": "'Sora', -apple-system, BlinkMacSystemFont, sans-serif",
"mono": "ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, monospace",
"heading": "'Sora', -apple-system, BlinkMacSystemFont, sans-serif",
"googleFontsImport": "https://fonts.googleapis.com/css2?family=Sora:wght@400;500;600;700;800&display=swap"
},
"typography": {
"baseFontSize": "15px",
"baseLineHeight": 1.6,
"h1Size": "2.25rem",
"h2Size": "1.625rem",
"h3Size": "1.25rem",
"h4Size": "1.125rem",
"letterSpacing": "-0.01em",
"headingWeight": 700,
"bodyWeight": 400
},
"radii": {
"xs": "4px",
"sm": "8px",
"md": "12px",
"lg": "16px",
"xl": "24px",
"2xl": "32px",
"full": "9999px"
},
"shadows": {
"xs": "0 1px 2px rgba(0, 0, 0, 0.04)",
"sm": "0 2px 4px rgba(0, 0, 0, 0.06)",
"md": "0 4px 12px rgba(0, 0, 0, 0.08)",
"lg": "0 8px 24px rgba(0, 0, 0, 0.1)",
"xl": "0 16px 48px rgba(0, 0, 0, 0.12)"
},
"layout": {
"productGridColumns": { "mobile": 2, "tablet": 3, "desktop": 4 },
"sidebarWidth": "240px",
"headerStyle": "sticky",
"footerColumns": 4,
"categoryDisplayMode": "sidebar-left"
},
"components": {
"buttons": {
"borderRadius": "xl",
"textTransform": "none",
"fontWeight": 600,
"padding": "12px 28px"
},
"cards": {
"borderRadius": "md",
"shadow": "none",
"hoverShadow": "md",
"border": false
},
"badges": {
"borderRadius": "sm",
"textTransform": "uppercase",
"fontSize": "0.7rem",
"fontWeight": 700
},
"inputs": {
"borderRadius": "sm",
"borderColor": "border",
"focusRing": "accent"
}
}
}theme-tech.json (TechZone - key differences highlighted)
The tech theme uses sharp corners (radii.xs: 2px), blue accent (#3b82f6), Space Grotesk headings, and bordered cards with shadows:
{
"name": "TechZone",
"description": "Modern tech store with sharp corners, blue accent, and clean utility aesthetic",
"colors": {
"primary": "#0f172a",
"accent": "#3b82f6",
"accentHover": "#2563eb",
"accentLight": "#eff6ff"
},
"fonts": {
"sans": "'Inter', -apple-system, BlinkMacSystemFont, sans-serif",
"heading": "'Space Grotesk', -apple-system, BlinkMacSystemFont, sans-serif",
"googleFontsImport": "https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Space+Grotesk:wght@400;500;600;700&display=swap"
},
"radii": {
"xs": "2px",
"sm": "4px",
"md": "6px",
"lg": "8px",
"xl": "10px",
"2xl": "12px"
},
"components": {
"buttons": { "borderRadius": "sm" },
"cards": { "borderRadius": "sm", "shadow": "sm", "hoverShadow": "lg", "border": true },
"badges": { "borderRadius": "xs" }
}
}See theme.json Reference for complete token documentation.
page.json
Controls which component variant renders for each page and slot. Each store can have its own page config.
Full page.json example (Fashion Demo - default)
{
"pages": {
"product": {
"components": {
"layout": "masonry",
"gallery": "masonry",
"info-panel": "compact",
"card": "minimal",
"price": "standard",
"variant-picker": "swatch",
"quantity-stepper": "standard",
"tabs": "accordion"
},
"sections": {
"showBreadcrumbs": true,
"showSizeGuide": true,
"sizeGuideVariant": "table",
"showRelated": true,
"showUpsell": true,
"showRecentlyViewed": true,
"showReviews": true,
"reviewsPosition": "tabbed"
}
},
"category": {
"components": {
"card": "minimal",
"filter": "sidebar",
"sort": "standard",
"pagination": "standard"
},
"gridColumns": { "mobile": 2, "tablet": 3, "desktop": 4 },
"filterPosition": "sidebar-left",
"showSubcategories": true
},
"cart": {
"components": {
"drawer": "slide",
"line-item": "standard",
"summary": "standard"
},
"showRecommendations": true,
"showProgressBar": true
},
"engagement": {
"components": {
"newsletter": "popup"
}
},
"header": { "variant": "centered" },
"footer": { "variant": "mega" },
"homepage": {
"components": {
"hero": "split",
"promo-grid": "3up"
}
},
"search": {
"components": {
"bar": "overlay",
"results": "standard"
}
}
}
}page-tech.json (TechZone - key differences)
The tech store uses standard cards (not minimal), tabbed product info (not accordion), mega header, standard footer, and a fullwidth hero:
{
"pages": {
"product": {
"components": {
"card": "standard",
"tabs": "tabbed"
},
"sections": {
"showSizeGuide": false
}
},
"category": {
"components": { "card": "standard" },
"gridColumns": { "mobile": 2, "tablet": 3, "desktop": 3 },
"cmsInsertion": "row",
"cmsInsertPosition": 3
},
"header": { "variant": "mega" },
"footer": { "variant": "standard" },
"homepage": {
"components": { "hero": "fullwidth" }
}
}
}See page.json Reference for all available slots and variants.
package.json Scripts
| Script | Command | Description |
|---|---|---|
dev | wrangler dev | Local development server |
deploy | wrangler deploy | Deploy to Cloudflare |
build | build:css && build:js | Build all assets |
build:css | unocss ... --out-file public/styles.css | Generate CSS |
build:js | esbuild ... --outfile=public/controllers.js.txt | Bundle JS |
manifest | node scripts/generate-manifest.js | Generate component manifest |
test | vitest run | Run tests |
types | wrangler types | Generate TypeScript types |
All scripts are run via Bun (bun run build, bun run dev, etc.). The Maho CLI command ./maho storefront:build handles Bun installation automatically.
File Reference
| File | Purpose | Docs |
|---|---|---|
wrangler.toml | Workers config | This page |
stores.json | Store → theme mapping | This page |
theme.json | Design tokens | Theme Reference |
page.json | Variant config | Page Config |
uno.config.ts | UnoCSS config | UnoCSS |
manifest.json | Component metadata | Variant System |
deploy.sh | Deploy script | Deployment |
Source: wrangler.toml, stores.json, package.json