Installation
Install typed Payload CMS blocks with the Payload Components CLI. It wires each block, regenerates Payload types, and updates the admin import map.
Use the Payload Components CLI to add a typed block to a supported Payload CMS v3 project using Next.js App Router. One command installs the block's source files and dependencies, then registers it in the Pages layout and RenderBlocks renderer.
After the block is wired, the CLI runs generate:types and generate:importmap. This refreshes your Payload types and admin import map before the install is recorded in .payload-components/state.json.
Requirements
The installer verifies the target project shape before it mutates anything. If a requirement is missing, it stops rather than leaving a half-wired repo.
Your project must run these majors:
| Dependency | Version |
|---|---|
payload | v3 |
next | v15 or v16 |
…and it must already contain the website-style block layout the installer patches into:
Plus package.json scripts for generate:types and generate:importmap, which the CLI runs after wiring.
Install a component
Choose an installable block from the full component catalog, then run the block's add command from the root of your Payload project. Every component page shows its exact command; examples:
npx payload-components add hero-basicPreview an install before making any changes:
npx payload-components add hero-basic --dry-runThe dry run performs the normal project and dependency validation, then lists
the component files, RenderBlocks.tsx renderer mapping, Pages/index.ts block
registration, dependencies, and generation commands. It does not write files,
install packages, run commands, or update .payload-components/state.json.
Optional draft demo
Demo content is opt-in. Add --demo to a normal install to write a runnable
TypeScript seed script strictly after the component install succeeds:
npx payload-components add hero-basic --demo
pnpm exec payload run payload-components/seed-hero-basic.tsIf the component is already installed, write the same script without rerunning the installer:
npx payload-components seed hero-basic
pnpm exec payload run payload-components/seed-hero-basic.tsThe first command only writes payload-components/seed-hero-basic.ts; it does
not connect to your database. The CLI also prints the equivalent payload run
command for npm, Yarn, Bun, or pnpm. Run that generated script yourself from the
project root against the database you intend to modify.
The seed command fails closed
seed requires a current installed-state record, compatible dependencies,
every manifest and registry-dependency file, and every Payload layout and
renderer fragment before writing the script. If any check is incomplete or
stale, it exits non-zero, reports why, and writes nothing. Fix the install with
npx payload-components add hero-basic, then retry.
The generated file begins with a versioned ownership marker. Regeneration uses
an atomic sibling-file rename and refuses to overwrite an unmarked file, a
symlink present during generation, a non-file, or any path outside the detected
project. This keeps an existing consumer seed from being mistaken for CLI-owned
output. The CLI also creates a mode-0600 private ownership record at
.payload-components/demo-state/hero-basic.json. Keep that file with the
project: deleting or changing it intentionally makes the generated script refuse
to touch existing demo content.
For hero-basic, the generated document contract is deliberately specific:
- Page slug:
payload-components-demo-hero-basic - Page title:
Payload Components demo — Hero Basic - first block marker prefix:
payload-components:demo:hero-basic - generated media marker prefix:
payload-components:demo:hero-basic:media - private ownership: a random token, per-create operation tokens, and the exact Page and Media IDs
The script requires the detected Pages collection to support drafts. It aborts
before querying or mutating content otherwise. A successful run writes
_status: 'draft', so you must review and publish explicitly. On first run, an
existing same-slug Page is a collision unless it is the single exact result of
an interrupted, locally journaled create—matching public title or a generic
marker is not enough. Before creating, the script atomically records a unique
operation token. After creation, it saves the returned Page ID. A rerun updates
only that exact ID after verifying the expected slug, title, block type, and
tokenized marker; the update also uses overrideLock: false. If the process
stopped after the database commit but before the ID save, the next run adopts
only the single document with the exact journaled token. Missing or mismatched
local state causes a hard failure before unsafe mutation.
For components with required uploads, the script journals the Media create,
creates one ownership-marked placeholder Media document, immediately saves its
returned ID, and reuses only that exact ID on a rerun. If the Media ID save or
Page write fails, the journaled operation or saved Media ID makes a retry
idempotent.
Marker-like or duplicate Media without the matching private record causes a
refusal; the generated script never deletes Media. Placeholder files use a
unique OS temporary directory that is removed in a finally block. All
mutations use the same revalidation-safe context as the project smoke path. The
operator-run script uses overrideAccess: true intentionally, so inspect the
generated file and your environment before executing it.
What the CLI does
The wrapper CLI owns the Payload-specific work that direct registry installation cannot handle:
Validate the target project shape — refuse to touch a repo that isn't a supported Payload v3 + Next.js project.
registry-build builds the checked-in manifest, then registry-add adds the registry item and installs its source files.dependency-install installs missing component dependencies so the block compiles in your project.
fragment-apply registers the block in RenderBlocks and the Pages layout field.post-install runs (generate:types, generate:importmap) and writes .payload-components/state.json.
When --demo is present, writing the demo script is a final sixth action after
the installed state above. A failed install never writes a demo script.
Doctor
Run a read-only health check before or after installing components:
npx payload-components doctordoctor validates the supported project shape, required post-install scripts,
and recorded component installs in .payload-components/state.json. It exits
non-zero when files, Payload fragments, dependency declarations, or install state
need attention.
Already have a block file that is not appearing in the editor or on the page? Use the four-step Payload block troubleshooting checklist to match the symptom to the missing registration, render map, type, or import-map step.
TypeScript cannot resolve @/payload-types, or a new block interface is missing?
Use the Payload 3 generated-types repair guide
to check the output path, registration order, and generation command.
Want to see how one real block moves from config to the editor and frontend?
Follow the hero-basic implementation from Block config through live rendering.
Idempotency
Running the same install twice should not duplicate imports, block registrations, or layout entries. The installer verifies files, fragments, dependencies, and recorded state before deciding whether any work is needed.
Direct registry installs
Every block is also published to a public, shadcn-compatible registry, so you can pull a block's files with the plain shadcn CLI — useful for inspecting a block or dropping one into a non-Payload project.
Register the namespace once in your project's components.json:
{
"registries": {
"@payload-components": "https://www.payload-components.xyz/r/{name}.json"
}
}Then add any block by name:
pnpm dlx shadcn@latest add @payload-components/hero-basicOr install a single item straight from its URL, without configuring the namespace:
pnpm dlx shadcn@latest add https://www.payload-components.xyz/r/hero-basic.jsonA direct shadcn add only copies the block's source files and its shadcn UI
dependencies. It does not register the block in RenderBlocks, wire the
Pages layout field, install Payload dependencies, or run generate:types and
generate:importmap. For a real Payload project, use payload-components add —
it does all of that and records install state.
payload-components add vs shadcn add
Both install registry items; they differ in where they stop. shadcn add copies a component's files. payload-components add also registers, renders, types, and import-maps the Payload block.
Fix Payload 3 payload-types errors
Fix missing, stale, or unresolved Payload 3 generated types before they break a block install.