Overview

The multi-tenant CMS toolkit. Content rows live in the Convex deployment (packages/convex); this package owns everything that gives those rows meaning — the field descriptors that define every content shape, the editor primitives the admin app mounts at /cms, the block render layer the storefront uses, and the cache taxonomy both sides of the invalidation contract share.

Built on Payload 3.x before the Convex migration — see .specs/2026-05-30-convex-migration/ in the repo for that history. There is no Payload (and no database connection) anywhere in the current package.

For the canonical reference, see the README on GitHub.

Why

A single deployment serves many tenants, and each tenant needs its own pages, articles, navigation, business data, and per-product/collection metadata. This package exists so the platform has exactly one canonical definition of CMS content:

  • One schema, many tenants. Every content table keys on the shop's id (shop == tenant). The field descriptors here generate the Convex table validators, the editor-action wrappers, and the storefront read-contract types (pnpm cms:gen), so the editor, the read contract, and the storage schema can never drift apart.
  • Shopify-aware blocks, no Shopify dependency in the CMS. The block model is defined here; data loaders for collection / vendors / overview blocks are injected by the storefront at the BlockRenderer boundary.
  • Cache invalidation by construction. The cms tag taxonomy is declared once (cache-descriptor.ts, free of server-only) and consumed from both sides: the Next.js read adapter (./cache) and the Convex revalidation pipeline, which derives identical tags from each publish event.

In this section

  • Overview — this page
  • API — the surviving pure helpers (resolveLink) and where reads went
  • Blocks — block model and the BlockRenderer dispatch component
  • Collections — content collections, descriptors, and editor access
  • Editor — the manifest-driven authoring stack
  • Responsive fields — per-breakpoint values, device presets, and the reusable primitive
  • API Reference — auto-generated from TypeScript source

On this page