Skip to content

payload

@evolve-framework/payload · v1.0.0

The Payload CMS for Evolve: a plugin that sets up your Payload config with the pages, media and content blocks of the shared content contract, and a module that serves that contract from the same database.

When to use

Use it when Payload is your CMS, typically self-hosted next to the commerce engine. The admin app loads evolveCms() in its Payload config, and the storefront's content subgraph runs PayloadModule from the very same config, talking to the database through Payload's Local API. Every collection can be scoped to a store, and catalog pickers can let editors choose products and categories from the commerce engine. Use @evolve-framework/contentful or @evolve-framework/storyblok instead for those CMSes.

Get started

  1. Install the package with the peer dependencies it needs. It comes from the Evolve registry, which needs a one-time sign-in.

    pnpm add @evolve-framework/payload @evolve-framework/core @payloadcms/richtext-lexical @payloadcms/ui fastify graphql graphql-yoga payload react
    Requirements10
    @evolve-framework/core>= 1.0.0 < 2.0.0
    @payloadcms/plugin-multi-tenant>= 3.87.0 < 4.0.0optional
    @payloadcms/richtext-lexical>= 3.87.0 < 4.0.0
    @payloadcms/ui^3
    @types/node>=22optional
    fastify>= 5.12.1 < 6.0.0
    graphql>= 16.0.0 < 17.0.0
    graphql-yoga>= 5.21.3 < 6.0.0
    payload>= 3.87.0 < 4.0.0
    react^19

For example:

// payload.config.ts, loaded by the admin app and by the subgraph
import { buildConfig } from "payload";
import { evolveCms } from "@evolve-framework/payload/config";
import { db } from "./db.ts"; // your database adapter, e.g. postgresAdapter()
export default buildConfig({
db,
secret: process.env.PAYLOAD_SECRET ?? "",
// the editor and the rest of your Payload config
plugins: [...evolveCms()],
});

Modules

PayloadModule

Module wiring the Payload resolvers and typedefs into a Domain Service.

Unlike the Contentful and Storyblok modules this one speaks no HTTP to the CMS: it boots Payload's Local API in-process and reads straight from the database the admin app writes to. There is no delivery client, no API key and no page cache to invalidate -- and no webhook route, because the content-modified events are published by an afterChange hook running in the admin process.

Only one PayloadModule instance per process is supported -- the Payload instance and the mapper registry are held as module-scope singletons.

import { PayloadModule } from "@evolve-framework/payload";
new PayloadModule(options: PayloadModuleOptions)
OptionTypeDescription
configSanitizedConfig | Promise<SanitizedConfig>

The project's payload config -- the very same module the admin app loads. Import it directly (import config from "./payload.config.ts"); the module boots the Local API from it during init().

articlesPerProduct?number

How many articles a product shows at most. Defaults to 4.

blocks?ContentBlockDef[]

The complete set of content blocks the module serves. Defaults to the built-in contentBlocks; spread it to add or replace, e.g. blocks: [...contentBlocks, myBlock] (a block whose id matches a built-in replaces it). Each block's mapper is registered and its SDL fragment merged into the served schema.

More

Pass the same array you passed to evolveCms() in the payload config.

locales?LocaleMap

Maps store-context locales (nl-NL) onto Payload locale codes. Defaults to stripping the region subtag.

homePath?string

Path the site root is stored under. Frontends ask for the root with an empty path; this is what that resolves to. Defaults to "homepage".

multiTenant?boolean

Whether the config is tenant-scoped, i.e. whether reads must match the request's storeKey against a tenant. Must mirror the multiTenant option passed to evolveCms(). Defaults to true.

tenants?TenantMap

Maps store keys onto tenant slugs, for stores that share a tenant or whose tenant is named differently. A store missing from it reads the tenant whose slug is its store key. When set, catalog pages are kept in the mapped tenants only; when not, in every tenant.

mappers?((registry: MapperRegistry) => void)

Optional callback invoked with the pre-populated MapperRegistry. Use it to add or override mappers for custom Payload blocks.

ContentBlockDef8The fields of blocks.
FieldTypeDescription
idstring

Payload block slug, e.g. "promo_list". Matches the incoming blockType.

typenamestring

Output GraphQL typename, e.g. "PromoList".

typeDefs?string

SDL fragment for the block's output type (+ its union membership). Omitted for blocks with no GraphQL surface of their own.

payload?Block

The Payload block config registered into config.blocks. Omitted for defs that describe a collection rather than a block (pages) or that declare a union member without a Payload counterpart.

More

Any field whose name matches a declared slot and whose type is blocks has its blockReferences filled in from that slot -- see applySlotReferences. Write those fields with an empty blockReferences: []; the slot declaration is the source of truth.

groups?string[]

Groups this block is a member of (which slots it can fill).

slots?Record<string, Slot>

Slots this block exposes (what it can contain).

mapper?ContentBlockMapper

Maps a Payload block of this type onto the block's GraphQL type. Omitted only for defs whose type is never mapped on its own -- pages (see pageMapper) and bare union declarations.

pageMapper?PageMapper

Maps a document of this page type's collection onto its GraphQL page. Set only on page types, which the page resolvers dispatch to by id.

Extends AbstractModule<PayloadLoaderContext>.

Commands

Installing this package adds these commands to the evolve CLI.

  • evolve eject: Eject built-in blocks, collections or fields into your project so you own them

Entry points

@evolve-framework/payloadPayloadModule, the built-in content blocks and defineContentBlock for your own, and catalog page sync.67 exports
@evolve-framework/payload/configevolveCms, the Payload plugin with the pages and media collections, multi-tenancy by store and the catalog pickers, plus the collections on their own.41 exports
@evolve-framework/payload/graphql/contextThe request context the module's resolvers expect.3 exports
@evolve-framework/payload/graphql/typesThe generated GraphQL types of the content contract.237 exports
@evolve-framework/payload/testingA test configuration, tenant seeding and a test executor.3 exports
@evolve-framework/payload/adminThe admin UI components for picking products, variants and categories from the catalog.10 exports
@evolve-framework/payload/migrations/drop-removed-schemaA predefined migration, for payload migrate:create --file, that drops the tables, enums and columns the config no longer declares.2 exports