Skip to content

Payload Collection CLI - Specifications & FAQs

CLI Syntax

bash
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 KeyDefaultDescription
-c, --config-fileconfigFile(none)Path to a configuration file (named export required).
-j, --config-jsonconfigJson(none)Inline JSON string for configuration. Takes precedence over configFile.
-n, --config-export-nameconfigExportNamecliConfigThe 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:

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.

OperationInput FormatDescription
createJSON/JSONLCreates new records.
updateJSON/JSONLUpdates existing records (requires lookupField).
deleteJSON/JSONL/IDDeletes records (requires lookupField).
upsertJSON/JSONLUpdates if found, otherwise creates.
patchJSON (Patch)Executes a standard JSON Patch (RFC 6902).
syncJSON/JSONLSynchronizes 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 where field equals value.
  • /-: Appends a new document (used in add operations).

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.

typescript
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 OptionDefaultDescription
lookupFieldidThe 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

OperationlookupField UsageonNotFound Usagedefaults Usage
createN/AN/AApplied to new doc
updateRequired to find docN/AApplied to update data
deleteRequired to find docN/AN/A
upsertRequired to find docN/AApplied (new/update)
patchRecommended for pathsApplied to related docsApplied to full-doc patch only
syncRequired to match docsApplied to related docsApplied (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.

typescript
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.