← Documentation

Documentation

Concepts

EmDash first

EmDash owns content modeling, auth boundaries for the admin, media storage, and how data lands in your database. DashCommerce adds a commerce domain on top: products, cart, checkout, orders, and the operations UI to manage them — exposed through the same EmDash admin surfaces you already use.

This layering matters. You are not installing a headless commerce backend plus a separate CMS. You are installing one CMS (EmDash) with one plugin (DashCommerce) that adds a commerce domain to the same data and admin surface. Content pages, blog posts, product descriptions, and order lookups all share one authentication model, one storage layer, one deploy.

Typed collections

Product definitions lean on EmDash's collection model — typed schemas validated at build and write time. The goal is to avoid "stringly typed" Woo-style meta fields for core commerce entities unless you truly need them for customization.

Plugins cannot register host content collections directly — you declare a products collection (and product taxonomies) in seed.json. Use the dashcommerce-merge-seed CLI or mergeDashCommerceSeed() from @dashcommerce/core so the JSON stays aligned with the plugin; then emdash seed applies it. See Getting started.

There are six product types in core: simple, variable (size × color etc.), grouped (bundles), external (affiliate links), subscription, and digital-download. They share a base schema and layer type-specific fields on top.

Edge-native storefront

Storefront routes and components are designed to run in edge-friendly deployments — Cloudflare Workers, Vercel Edge, Netlify Edge — consistent with EmDash's Astro-native story. The runtime entry avoids Node built-ins so it runs in Workers without polyfills. Heavy or privileged work stays on the server or in trusted worker contexts — not in the client bundle by default.

Practically, this means: product pages ship zero JavaScript by default, cart state hydrates only where needed, and checkout calls Stripe's Payment Element from a controlled island. Performance budgets are set by the framework, not renegotiated per feature.

Stripe primitives, directly

DashCommerce does not abstract Stripe behind a custom payment interface. Payment Intents are Payment Intents. Subscriptions are Stripe Subscriptions with all the lifecycle events Stripe supports. Connect means transfer_data and application_fee_amount on a PaymentIntent. This keeps the surface area small: if something works in Stripe, it works in DashCommerce; if Stripe changes a primitive, DashCommerce follows.

Every Stripe webhook is idempotent via unique-indexed Stripe event IDs. Replaying a webhook — which Stripe sometimes does at least-once — cannot double-process an order, double-charge a subscription, or double-issue a refund.

Money as integer minor units

All amounts are stored as integer cents (or equivalent minor units for other currencies). No floats, no currency-string mixing. Prices, taxes, shipping, discounts, and totals are all number values in minor units. Conversions for display happen at the render boundary with the product's currency.

"WooCommerce-shaped" — not Woo-compatible

Feature categories (shipping zones, coupons, subscriptions, marketplace payouts) are intentionally familiar if you've operated Woo stores, but there is no drop-in WordPress migration. Moving from Woo means rethinking content and catalog in EmDash terms — see Migrate from WooCommerce for the realistic scope.

Where DashCommerce isn't the right tool

DashCommerce does not offer a Merchant-of-Record service. If you sell digital goods to a global customer base and want VAT / sales tax handled for you, Lemon Squeezy or Paddle is the correct tool. DashCommerce also does not ship a point-of-sale, nor a polished merchant dashboard in the Shopify sense — if operational simplicity matters more than ownership and cost, see DashCommerce vs Shopify.

FAQ

What is EmDash CMS?
EmDash is an open-source, Astro-native content management system — a WordPress successor designed to run on the edge (Cloudflare Workers, Vercel, Netlify). It handles collections, admin UI, media, and database. DashCommerce is a plugin that adds commerce on top. See github.com/emdash-cms/emdash.
What does 'typed end-to-end' mean?
Every product, order, customer, and subscription in DashCommerce has a TypeScript type, validated via Zod at write and build time. Your product schema, storefront routes, admin components, API endpoints, and Stripe webhook handlers all share the same type definitions. No 'stringly typed' meta fields for core commerce entities unless you explicitly extend the schema.
What does 'edge-native' mean in practice?
DashCommerce storefronts run on edge compute (Cloudflare Workers, Vercel Edge Functions) close to the user. The plugin avoids Node built-ins at runtime so it runs in Workers without shims. Heavy work (database writes, Stripe API calls) stays on the server; zero JS ships to the client by default on storefront pages.
Is DashCommerce WooCommerce-compatible?
No. DashCommerce covers the same feature categories as WooCommerce — products, cart, subscriptions, marketplace, multi-currency — but uses its own data model, schema, and admin. There is no drop-in WordPress migration; moving from WooCommerce means rethinking content and catalog in EmDash terms. See Migrate from WooCommerce.
How are products defined?
Products live in a typed products collection declared in your EmDash seed.json. The six product types (simple, variable, grouped, external, subscription, digital-download) share a base schema plus type-specific fields. The dashcommerce-merge-seed CLI merges DashCommerce's required collection definitions into your seed file so the schema stays aligned with the plugin.
Where does money live?
All money values are stored as integer minor units (cents for USD, pence for GBP, etc.) — never floats. Stripe is the source of truth for payment state; DashCommerce persists order and subscription shadows indexed by Stripe IDs. Webhooks are idempotent via unique-indexed Stripe event IDs — replaying a webhook cannot double-process an order.
What is the sandboxed plugin model?
DashCommerce is an EmDash plugin, loaded via EmDash's plugin system. It runs in the same process as EmDash but with a defined API surface — no access to arbitrary EmDash internals. This means plugins can be safely composed without trust issues; it also means DashCommerce is constrained to what EmDash's plugin API exposes.
Does DashCommerce handle tax?
Flat-rate tax is supported by default. Stripe Tax integration is on the roadmap and can be enabled with one env var when ready. For complex jurisdictions (EU VAT, US destination-based sales tax), wire Stripe Tax and confirm your liability — DashCommerce is not a Merchant of Record. For MoR-handled tax, see DashCommerce vs Lemon Squeezy.