Skip to content

Configuration Reference ​

All configuration files and environment variables used by the Maho Storefront.

wrangler.toml ​

Cloudflare Workers deployment configuration.

toml
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 = true

Environment Variables ​

VariableTypeRequiredDescription
MAHO_API_URLstringYesBase URL of Maho backend
SYNC_SECRETstringYesShared secret for /sync and /cache endpoints. Fails closed — an unset or placeholder value rejects all requests.
DEV_SECRETstringNoEnables the dev toolbar and dev token authentication. If not set, the toolbar system is completely disabled.
MAHO_API_BASIC_AUTHstringNoHTTP Basic auth (user:pass) for the backend, injected server-side when proxying.
STORESstring (JSON)NoArray of { code, name, url, apiUrl? } defining the stores this Worker serves.
USE_CF_IMAGE_RESIZEstringNo"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:

  1. 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).
  2. 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/thumbnail roles 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 ​

SettingDescription
bindingVariable name in Worker code (env.CONTENT)
idCloudflare 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 KeyTypeDescriptionDocs
config:password_gatebooleanEnable/disable the password gatePassword Gate
config:storefront_passwordstringPassword visitors must enter when gate is activePassword Gate
bash
# 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.

json
{
  "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"
}
FieldTypeDescription
storesobjectStore code → config mapping
stores[code].themestringTheme name (maps to theme-{name}.json)
stores[code].pageConfigstringPage config filename
defaultThemestringFallback theme for unmapped stores
defaultPageConfigstringFallback 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)
json
{
  "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:

json
{
  "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)
json
{
  "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:

json
{
  "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 ​

ScriptCommandDescription
devwrangler devLocal development server
deploywrangler deployDeploy to Cloudflare
buildbuild:css && build:jsBuild all assets
build:cssunocss ... --out-file public/styles.cssGenerate CSS
build:jsesbuild ... --outfile=public/controllers.js.txtBundle JS
manifestnode scripts/generate-manifest.jsGenerate component manifest
testvitest runRun tests
typeswrangler typesGenerate 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 ​

FilePurposeDocs
wrangler.tomlWorkers configThis page
stores.jsonStore → theme mappingThis page
theme.jsonDesign tokensTheme Reference
page.jsonVariant configPage Config
uno.config.tsUnoCSS configUnoCSS
manifest.jsonComponent metadataVariant System
deploy.shDeploy scriptDeployment

Source: wrangler.toml, stores.json, package.json