AI Coding Context
TIP
This page consolidates the entire project documentation into a single Markdown block for easy copying into AI coding assistants. Use the copy button at the top right of the code block below.
markdown
# payload-collection-cli
[](https://github.com/payload-cc/payload-collection-cli/actions/workflows/ci.yml)
[](https://www.npmjs.com/package/@payload-cc/payload-collection-cli)
[](https://github.com/payload-cc/payload-collection-cli/blob/main/LICENSE)
[](https://payload-cc.github.io/payload-collection-cli/)
**The missing CLI for Payload 3.0. Manage collections without writing boilerplate scripts.**
<p align="center">
<img src="https://raw.githubusercontent.com/payload-cc/payload-collection-cli/main/docs/public/logo.png" alt="Payload Collection CLI Logo" width="200"/>
</p>
<p align="center">
🚀 <strong><a href="https://payload-cc.github.io/payload-collection-cli/">Official Guide</a></strong>
•
🤖 <strong><a href="https://payload-cc.github.io/payload-collection-cli/ai.html">AI Context Page</a></strong>
</p>
---
## Why?
Payload 3.0 is powerful, but performing simple data operations often requires writing one-off scripts. **payload-collection-cli** turns your terminal into a direct interface for your collections, supporting intelligent relation lookups by name/slug instead of cryptic IDs.
## Features
- ⚡️ **Zero Scripting:** Run CRUD operations directly from your terminal.
- 🔍 **Relation Lookup:** Resolve relationships using `name`, `email`, or `slug`.
- 📄 **Batch Processing:** Support for both JSON strings and JSONLines (`.jsonl`) files.
- ⚙️ **Configurable:** Define your lookup logic in a simple external config.
- 🛡 **Native Performance:** Uses Local API to ensure all Hooks and Validations run.
## Installation
```bash
pnpm add @payload-cc/payload-collection-cli
# or npm install @payload-cc/payload-collection-cli
```
## Quick Start
You can immediately start using the commands without any configuration for basic insertions/updates!
**Command Syntax**:
```bash
npx @payload-cc/payload-collection-cli [options] <collection-slug> <operation> <file or string>
```
**Examples**:
```bash
# Bulk create/upsert from jsonlines
npx @payload-cc/payload-collection-cli posts upsert data.jsonl
# Simple JSON update
npx @payload-cc/payload-collection-cli users update '{"email": "user@example.com", "name": "New Name"}'
# With explicit mapping configuration
npx @payload-cc/payload-collection-cli -c ./my-map.config.ts users upsert data.jsonl
```
## Available Actions
- `create`: Create new records.
- `update`: Update existing records based on `lookupField`.
- `delete`: Delete records.
- `upsert`: Update if existing, create if not.
## Specifications & FAQ
For detailed configuration options (including `package.json` defaults, relation mappings, `onNotFound` behaviors, and cross-file imports), please refer to the [Specifications & FAQ](/references/specs_detail.md).
## Development & CI/CD
- Tests are powered by `vitest` to remain fast and lightweight.
- GitHub Actions automatically run checks on PRs, and publish the `dist/` bundle (excluding test codes and local configs) when a new Release is created on GitHub!
---
# Examples & Use Cases
This page showcases live examples of the **Payload Collection CLI** in action, automatically generated from our E2E test suite. Each section below represents a verified scenario, including the sample data and any custom mapping configuration used.
[[SCENARIO_EXAMPLES_BUNDLE]]
> [!TIP]
> All these examples are extracted directly from the `e2e-tests/scenarios` directory and are automatically verified on every CI run to ensure they remain perfectly functional with the latest Payload CMS version.
---
# 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` 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`:
```json
{
"payload-collection-cli": {
"configFile": "./payload-collection-cli.config.ts",
"configExportName": "myCustomConfig",
"configJson": "{\"mappings\": { \"users\": { \"lookupField\": \"email\" }}}"
}
}
```
---
## Configuration (`cliConfig`)
The CLI strictly looks for a **named export** in the configuration file (defaulting to `cliConfig`). **Default exports are not supported.**
### 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 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. |
---
## 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.