Skip to content

Payload

Payload powers the two CMS control planes. The CMS apps are product surfaces, not generic admin dashboards.

  • apps/cms-customer is the customer/deployment operator control plane.
  • apps/cms-leverage is the Leverage-owned internal product improvement and operations control plane.
  • @repo/payload-cms-auth and @repo/payload-email hold shared CMS integration helpers.
  • Payload native auth owns CMS operator accounts. Better Auth remains the web-user authority.

Decision: use two separate Payload apps instead of one shared CMS app.

The split keeps customer-local settings, customer-visible review surfaces, Leverage-owned product improvement workflows, databases, service credentials, and deployment boundaries separate. Customer-cluster release paths must never include Leverage-owned CMS credentials or internal-only configuration.

  1. Read Payload release notes, the database adapter docs, and migration notes for the target version.

  2. Compare against a fresh Payload blank MongoDB template before choosing CMS companion package versions. Use a gitignored temp directory, skip dependency installation and agent setup, then inspect only the generated package.json:

    Terminal window
    mkdir -p tmp/payload-template-compare
    cd tmp/payload-template-compare
    bunx create-payload-app@latest -n payload-template-blank -t blank --use-bun --no-deps --no-agent

    Select MongoDB when prompted, because both CMS apps use @payloadcms/db-mongodb. Keep Payload-owned packages on the template’s package line even when the registry has a newer patch for a companion package such as Next, React, or eslint-config-next. Do not downgrade an already-newer configured package just to match the template unless the human explicitly approves that downgrade.

  3. Keep payload and all @payloadcms/* packages aligned across both CMS apps:

    Terminal window
    # from apps/cms-customer
    bun add --exact payload@$PAYLOAD_VERSION @payloadcms/db-mongodb@$PAYLOAD_VERSION @payloadcms/next@$PAYLOAD_VERSION @payloadcms/richtext-lexical@$PAYLOAD_VERSION @payloadcms/ui@$PAYLOAD_VERSION
    # from apps/cms-leverage
    bun add --exact payload@$PAYLOAD_VERSION @payloadcms/db-mongodb@$PAYLOAD_VERSION @payloadcms/next@$PAYLOAD_VERSION @payloadcms/richtext-lexical@$PAYLOAD_VERSION @payloadcms/ui@$PAYLOAD_VERSION
  4. Keep @repo/payload-cms-auth and @repo/payload-email peer/dependency ranges aligned to the selected Payload line.

  5. Regenerate Payload artifacts where relevant:

    Terminal window
    bun run --cwd apps/cms-customer generate:importmap
    bun run --cwd apps/cms-customer generate:types
    bun run --cwd apps/cms-leverage generate:importmap
    bun run --cwd apps/cms-leverage generate:types
  6. For data-shape changes, use Payload migrations only when there is existing data to transform. With MongoDB, Payload’s docs say migrations may be needed only once in a while, or never, unless existing documents need to move from one shape to another.

  7. Run both CMS typechecks and integration lanes.

  • Do not collapse cms-customer and cms-leverage into one app or one account store.
  • Do not add Leverage-owned credentials, services, or internal CMS config to customer-cluster manifests.
  • Do not add historical single-CMS aliases such as CMS_BASE_URL.
  • apps/cms-customer/src/payload.config.ts
  • apps/cms-leverage/src/payload.config.ts
  • apps/cms-customer/package.json
  • apps/cms-leverage/package.json
  • packages/payload-cms-auth/
  • packages/payload-email/
  • docs/features/cms-control-plane-split/spec.md
  • docs/features/authentication/spec.md