Payload Collection CLI - Specifications & FAQs
CLI Syntax
npx @payload-cc/payload-collection-cli [options] <collection-slug> <operation> <file or string>Command Options
The following options can be set either via CLI flags or as defaults in your package.json. Note that positional arguments (collection-slug, operation, file or string) are mandatory and cannot be defaulted via package.json.
| CLI Option (Short/Long) | package.json Key | Default | Description |
|---|---|---|---|
-c, --config-file | configFile | (none) | Path to a configuration file (named export required). |
-j, --config-json | configJson | (none) | Inline JSON string for configuration. Takes precedence over configFile. |
-n, --config-export-name | configExportName | cliConfig | The name of the export to use from the configuration file. |
Overriding defaults in package.json
To use defaults, add a payload-collection-cli field to your package.json:
{
"payload-collection-cli": {
"configFile": "./payload-collection-cli.config.ts",
"configExportName": "myCustomConfig",
"configJson": "{\"mappings\": { \"users\": { \"lookupField\": \"email\" }}}"
}
}Technical Details
Operations
The CLI supports standard CRUD operations and advanced atomic updates via JSON Patch.
| Operation | Input Format | Description |
|---|---|---|
create | JSON/JSONL | Creates new records. |
update | JSON/JSONL | Updates existing records (requires lookupField). |
delete | JSON/JSONL/ID | Deletes records (requires lookupField). |
upsert | JSON/JSONL | Updates if found, otherwise creates. |
patch | JSON (Patch) | Executes a standard JSON Patch (RFC 6902). |
sync | JSON/JSONL | Synchronizes a collection with the provided data (Adds/Updates/Deletes). |
Identifier-based Paths (Entity JSON Patch)
For patch and sync operations, the CLI supports identifier-based paths to target specific documents without knowing their internal IDs:
/[field=value]/sub/path: Target a document wherefieldequalsvalue./-: Appends a new document (used inaddoperations).
TIP
While patch allows any field in the identifier path, it is recommended to use the lookupField defined in your mappings for consistency.
Example: /[email=user@example.com]/name targets the name field of the user with that email.
Configuration (cliConfig)
The CLI strictly looks for a named export in the configuration file (defaulting to cliConfig).
Relation Mappings
The core of the configuration is the mappings object in your config file.
export const cliConfig = {
mappings: {
users: {
lookupField: 'email', // Search by 'email' instead of 'id'
onNotFound: 'error', // 'error' | 'ignore' | 'create'
},
categories: {
lookupField: 'name',
onNotFound: 'create', // Auto-create the category if it doesn't exist
},
posts: {
defaults: {
category: 'default', // Inject this value if the field is missing from data
},
},
}
}| Mapping Option | Default | Description |
|---|---|---|
lookupField | id | The field used to find the target document. |
onNotFound | 'error' | Action when a document is not found ('error', 'ignore', 'create'). |
defaults | (none) | Default values injected into the record before processing. |
Interaction with Operations
| Operation | lookupField Usage | onNotFound Usage | defaults Usage |
|---|---|---|---|
create | N/A | N/A | Applied to new doc |
update | Required to find doc | N/A | Applied to update data |
delete | Required to find doc | N/A | N/A |
upsert | Required to find doc | N/A | Applied (new/update) |
patch | Recommended for paths | Applied to related docs | Applied to full-doc patch only |
sync | Required to match docs | Applied to related docs | Applied (new/update) |
NOTE
For patch operations, defaults are only applied if you are replacing the entire document (i.e., the patch path does not specify a sub-field). This prevents partial updates from inadvertently overwriting unrelated fields with default values.
FAQ
What is the correct behavior for upsert, update, and delete when the lookup field is missing?
The CLI strictly requires a unique identifier (the lookupField) to locate the target record. If the field is missing from your data, the CLI will throw an Error. This prevents accidental data corruption or duplicate records.
Can I include imports in my configuration file?
Yes! Since the configuration is loaded using jiti, you can use standard TypeScript/ESM imports.
import { DEFAULT_CATEGORY_NAME } from './src/constants';
export const cliConfig = {
mappings: {
posts: {
defaults: { category: DEFAULT_CATEGORY_NAME }
}
}
}Note: Imports are resolved relative to the configuration file's location.
Should I specify the ID in my data files?
If you use upsert, update, or delete without a custom lookupField, you must provide the id. For create, Payload will auto-generate the ID.