Payload CLI
The Payload CLI lets you work with your project from a terminal. You can use it to generate types, run migrations, inspect your setup, run jobs, and more.
The CLI loads the Payload Config from your project. Run commands from your project directory, or use PAYLOAD_CONFIG_PATH if your config is somewhere else.
The examples on this page use pnpm, but you can also use npx payload or the equivalent command for your package manager.
Built-in commands
Payload includes the following commands by default.
Core commands
Command | What it does |
|---|---|
| Generate the Admin Panel import map and TypeScript types, then run the project build. |
| Generate a database schema. Not every database adapter supports this command. |
| Generate the import map used by the Admin Panel. |
| Generate TypeScript types from your Payload Config. |
| Show help for all commands or for one command. |
| Print Node.js, package, operating system, memory, and CPU information. |
| Put jobs whose schedule is due into the queue. |
| Run jobs from the queue. |
| Run a local script in the Payload environment. |
Migration commands
Command | What it does |
|---|---|
| Run all pending migrations. |
| Create a migration. |
| Roll back the latest migration batch. |
| Clear the database and run all migrations again. |
| Roll back completed migrations and run them again. |
| Roll back all migrations. |
| Show which migrations have and have not run. |
Use --help to see the arguments and options for a command:
JSON output, help, and input
Every command accepts the global --json option. It returns a predictable response that scripts and coding agents can read:
You can place --json before or after the command. Commands that do not return data omit result. A failed command returns success: false, an error code, and an error message. Input validation errors also include the issues and the command's input schema.
In JSON mode, stdout contains exactly one JSON response while logs and other diagnostics stream to stderr. Parse stdout and display or store stderr separately. Do not use 2>&1: merging the streams makes stdout invalid JSON. Stderr intentionally remains a streaming text channel rather than a second buffered JSON value.
Set PAYLOAD_CLI_JSON to use JSON output for every command without repeatedly passing --json. This is useful when a script or coding agent runs several commands:
Unset the variable to return to regular terminal output, or use --no-json to override it for one command:
Payload can return help as JSON. This is useful for scripts and coding agents that need to know which commands exist and what input they accept.
For example, you would normally pass the migration name as an argument:
You can pass the same input as JSON with --input:
To read the input from a file, create migration-input.json:
Then add @ before the file path:
To read the same JSON from stdin, pipe it into the command and use -:
The JSON is validated in the same way as normal command arguments and options. Do not combine --input with other command input.
Custom commands
Use defineCLICommand to add your own command. Built-in and custom commands use the same API, help system, and input validation.
Define a command
The following example adds a seed command. Its code lives in seed.ts next to payload.config.ts:
The input schema defines the values the command accepts. Payload uses it to type args, validate input, and generate help. Add examples when a complete command makes the arguments easier to understand. Payload includes them in both terminal and JSON help.
The z export from payload is Zod Mini. Payload already uses Zod Mini, so this export adds no extra schema code to the bundle. Use strictObject for the root input schema so Payload can also generate JSON help.
Payload does not export regular Zod because its larger API would increase the bundle size. If you prefer regular Zod's chaining API, add zod to your own project and import it directly:
You can also use another schema library. Its schema must support both Standard Schema validation and Standard JSON Schema output.
Call getPayload() only when the command needs the Local API. Payload closes the instance when the command finishes.
Returning { result } makes that value available in JSON mode through --json or PAYLOAD_CLI_JSON. Return a number to set only the process exit code, or return { exitCode, result } when you need both. Payload sends payload.logger.* and console.* output to stderr in JSON mode. Use isJSON only when the command should behave differently in JSON mode.
Register the command
Add the command to cli.commands in your Payload Config. The map key becomes the command name:
Command paths use the same format as other PayloadComponent paths. A path without # uses the default export. Add #exportName to use a named export, or use the object form:
You can also pass a command directly. This example defines a small command inside the Payload Config:
Both forms work, but import paths are recommended. A direct command and all of its imports are loaded with the Payload Config, even when you are not using the CLI. An import path is only loaded when the CLI starts, so command-only dependencies stay out of the Payload Config bundle. Relative paths start from the folder containing payload.config.ts.
You can now run the seed command like any built-in command:
Arguments and options
By default, each field in input becomes a command option. Payload changes camelCase field names to kebab-case flags. For example, migrationName becomes --migration-name.
Use cli when a field needs different command-line behavior. For example, this makes filePath a positional argument:
Set a field to false to accept it only through --input. For less common cases, you can use an object to change the flag, argument position, or parser.
Add, replace, or disable commands
A new key in cli.commands adds a command. Using the name of a built-in command replaces it. Setting a command to false disables it:
After Payload loads the config, config.cli.commands shows the final list of built-in and custom commands.
Set cli itself to false to disable the entire Payload CLI:
Working with data from the CLI
Payload includes local commands for inspecting the config and working with collections and globals. They use the Local API and load the current Payload config on every invocation.
getCollectionSchema and getGlobalSchema also return their LLM instructions alongside schema. With --json, these are available as result.instructions. Read them before creating or updating content.
Start by discovering the available slugs and inspecting the input schema for a collection:
You can then query and update data without starting the development server:
To explicitly enforce access control:
The same option is named overrideAccess in JSON input:
createDocuments accepts a JSON array, keeping each document's data and optional upload file together:
Upload input can also use an external URL. Payload applies the upload collection's pasteURL, allow-list, safe-fetch, header, and file-size settings before creating or updating the document:
The trusted local CLI does not require an explicit allow-list. If one is configured, both the initial URL and redirects must match it. pasteURL: false disables URL uploads.
For updateDocument, pass the same object through --file:
For longer input, put the array in a file:
You can instead pass the command input through --input. Explicit arguments and options override values from the JSON input:
createDocuments and updateDocument return affected document IDs by default. Pass --returning when you need the complete documents:
Use --select with --returning to choose which fields come back:
The built-in data commands cover collection queries, counts, distinct values, create, update, delete, duplicate, and version operations. Globals have matching schema, read, update, count-version, find-version, and restore-version commands. Use payload help --json to list them or payload help <command> --json to inspect the exact input accepted by one command.
Running commands on a schedule
Use the global --cron option to run a command on a cron schedule:
This example runs queued jobs every five minutes. The CLI process stays open while the schedule is active.
Was this page helpful?