Skip to content

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

[![CI](https://github.com/payload-cc/payload-collection-cli/actions/workflows/ci.yml/badge.svg)](https://github.com/payload-cc/payload-collection-cli/actions/workflows/ci.yml)
[![NPM Version](https://img.shields.io/npm/v/@payload-cc/payload-collection-cli)](https://www.npmjs.com/package/@payload-cc/payload-collection-cli)
[![License](https://img.shields.io/github/license/payload-cc/payload-collection-cli)](https://github.com/payload-cc/payload-collection-cli/blob/main/LICENSE)
[![Documentation](https://img.shields.io/badge/docs-VitePress-blue)](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>
  &nbsp;&nbsp;•&nbsp;&nbsp;
  🤖 <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.