Commerce Quickstart
This quickstart stands up a product catalog and a storefront: the Commerce block pack (product cards, grids, pricing tables) on the front, the @wabbit/tome-catalog layer holding products underneath, and the @wabbit/tome-economy layer for orders and checkout. It assumes you have the block loop from Get Started working.
The Commerce block pack ships as @wabbit/tome-blocks-catalog-pack (its buyer-facing name is "Commerce Blocks"). It's a gated pack, so installing it needs an install token whose scope includes it.
What the starter already gives you
If you forked tome-starter, Commerce is already wired — the fork ships with all three pieces in package.json and composed in src/payload.config.ts:
@wabbit/tome-catalog— the five product collections and the product-type registry.@wabbit/tome-economy— orders, payments, prices, and the checkout adapters.@wabbit/tome-blocks-catalog-pack— the storefront blocks, bridged insrc/blocks/catalog-pack-bridge.*.
So on a starter fork you can skip to seeding products. The wiring sections below are the reference for how it's assembled — read them if you're adding Commerce to a bare Payload app, or to understand what your fork already did.
Install the packages
Make sure your .npmrc has the registry line and an install token (see Get Started) — the catalog pack is gated, so it needs the token. Then:
npm install @wabbit/tome-blocks-core @wabbit/tome-blocks-catalog-pack @wabbit/tome-catalog @wabbit/tome-economy@wabbit/tome-catalog is an optional peer of the block pack — the blocks render with static props even without it. Install it anyway: it's what lets the blocks read live product data, and it's the collection home for everything you sell. @wabbit/tome-economy adds the order and checkout machinery.
Wire the catalog layer
The catalog layer is a set of collection factories plus a product-type registry. Register the product types you sell before building the product collection (the type select reads them), then add the collections:
import {
createProductCollection,
createProductAttributeCollection,
createProductAttributeValueCollection,
createCategoryCollection,
createProductMediaCollection,
createEntitlementsCollection,
productTypeRegistry,
} from '@wabbit/tome-catalog'
// Register the product types your store uses (runs before createProductCollection):
productTypeRegistry.register({ value: 'physical', label: 'Physical', source: 'my-store' })
// ...then add these to your config's `collections` array:
createCategoryCollection({ maxDepth: 3, mediaCollection: 'media' }),
createProductAttributeCollection(),
createProductAttributeValueCollection(),
createProductCollection({ mediaCollection: 'media' }),
createProductMediaCollection({ mediaCollection: 'media' }),
createEntitlementsCollection({ usersSlug: 'members', membersSlug: 'members' }),This gives you the catalog-products, catalog-categories,catalog-attributes, catalog-attribute-values, and catalog-media collections. createEntitlementsCollection is what a completed order writes to — it's how a purchase grants access.
Wire the economy layer
Call initEconomy() once at module load (it registers the admin sidebar grouping), wire your order-complete handler, and add the collection factories:
import {
initEconomy,
createOrdersCollection,
createPaymentsCollection,
createPricesCollection,
createVendorEarningsCollection,
} from '@wabbit/tome-economy'
initEconomy()
// ...add to your config's `collections` array:
createOrdersCollection(),
createPaymentsCollection(),
createPricesCollection(),
createVendorEarningsCollection(),The economy layer ships two payment adapters: FreeAdapter (a zero-cost checkout that completes orders immediately — the default the starter demos with) and StripeAdapter (lazy-loads the Stripe SDK; only used when you add Stripe keys). The order-complete event is where you grant the entitlement — the starter wires this in src/lib/economy/orderHandlers.ts via registerStarterOrderHandlers(), which turns a completed order into a catalog entitlement (and an LMS enrollment for course products).
Register the Commerce blocks
The pack exposes six blocks: product-card, product-grid,category-strip, price-table, inventory-badge, and featured-product. Register them the same way as any pack — the one-call form:
import { blockRegistry, bundleRegistry } from '@wabbit/tome-blocks-core'
import { register } from '@wabbit/tome-blocks-catalog-pack'
register(blockRegistry, bundleRegistry)
// blockRegistry.resolveAll() now includes the six catalog blocksThe starter uses its bridge form instead: the config half (src/blocks/catalog-pack-bridge.config.ts) imports the block descriptors and spreads CatalogPackBlocks into the Pages layout field; the render half (src/blocks/catalog-pack-bridge.tsx) imports the components from @wabbit/tome-blocks-catalog-pack/render and folds catalogPackComponents into the master render map. When the @wabbit/tome-catalog layer is present, the blocks detect it and light up their rich data path; when it's absent they fall back to static props.
Seed or create products
The starter has a real seed. Running the demo seeds populate the catalog-products collection with live rows:
npm run demo:devThat runs with DEMO_SEED=1 SANDBOX_SEED=1 and creates a set of demo products (physical goods, course products, and block-bundle products), categories, and attributes — all idempotent, so re-running is safe. Prefer to start clean? Create a product by hand in /admin under the catalog-products collection — pick a type you registered, set it active, and it's live.
Render the storefront
With the pack registered, drop a product-grid or featured-product block onto a page's layout in /admin and publish. RenderBlocks paints it through the component map you wired in the previous step. The starter's auto-gallery route /blocks/catalog-pack shows every catalog block and variant.
Heads up — blocks vs. live data. In the starter, the seeded storefront blocks are fed hand-written demo product props, and the auto-gallery uses fabricated demo props — neither is bound to the seeded catalog-products rows out of the box. The starter demonstrates live product data on a separate /products route that queries catalog-products directly with @wabbit/tome-ui card primitives, not the pack's ProductGrid. Wiring the pack blocks to live rows (via the block's @wabbit/tome-catalog integration) is the step you own — budget for it, and treat "blocks render" and "blocks show my real products" as two separate checkpoints.
Checkout & the managed tier
The economy layer's FreeAdapter gives you an end-to-end checkout with no payment processor — good for course sign-ups, comps, and proving the order → entitlement flow. Add Stripe by installing the stripe SDK and configuring the StripeAdapter; the lazy import means you carry no Stripe dependency until you opt in.
The fully-managed Commerce capability tier — where we run the payment-flow and its liability with you — is set up through a request-access conversation, not a checkout button. If that's where you're headed, reach out. For what a subscription keeps buying you after install, see Versioning & updates.