# Generating Payload Migration

> Explains how to create and review Payload CMS migrations. Use this skill whenever the user changes Payload collections, globals, fields, indexes, relationships, database adapter-backed schema, or wants to generate, rename, review, or decide whether to create a Payload migration.

- Skill: `ilya-valasiuk/generating-payload-migration` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add ilya-valasiuk/generating-payload-migration`
- Raw SKILL.md: https://api.skillmd.com/api/skills/ilya-valasiuk/generating-payload-migration/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: ilya-valasiuk (https://skillmd.com/u/ilya-valasiuk)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/ilya-valasiuk/generating-payload-migration

---


# Generating Payload Migrations

This skill covers the end-to-end process for creating a Payload CMS database migration. It keeps schema changes source-driven, migration names descriptive, generated artifacts reviewed, and migrations from being run automatically.

## Step 1 - Update Payload Source Files

Modify the relevant Payload source of truth first:

- Collections: `src/collections/<CollectionName>.ts`
- Globals, if present: `src/globals/`
- Payload config: `src/payload.config.ts`
- Related field helpers, hooks, access logic, or constants when they affect schema

Use Payload collection/global/field config as the source of truth. Do not hand-write migration SQL for schema changes that Payload can generate from config.

## Step 2 - Generate the Migration

Run the migration creation command from the project root with a clear snake_case slug:

```bash
npm run migrate:create <migration_name>
```

The name becomes part of the generated files under `src/migrations/`:

- `src/migrations/<timestamp>_<migration_name>.ts`
- `src/migrations/<timestamp>_<migration_name>.json`

Choose the name carefully before generating. Use action-oriented names:

- `create_` - creating a new collection/table
- `add_` - adding a field, index, relationship, enum value, or constraint
- `remove_` / `drop_` - removing a database object
- `rename_` - renaming a field or collection-backed object
- `update_` / `change_` - modifying existing schema shape
- `migrate_` - transforming or moving existing data

Real project example:

```bash
npm run migrate:create create_regattas_collection
```

This generated:

- `src/migrations/20260707_125121_create_regattas_collection.ts`
- `src/migrations/20260707_125121_create_regattas_collection.json`

## Step 3 - Review Generated Artifacts

Open the generated `.ts`, `.json`, and `src/migrations/index.ts`.

Verify the TypeScript migration:

- `up()` contains only the expected schema changes.
- `down()` correctly reverses those changes.
- No unrelated collections, tables, fields, enums, indexes, or constraints are touched.

Verify the JSON snapshot:

- It includes the expected new or changed schema state.
- It does not contain surprising unrelated schema drift.

Verify `src/migrations/index.ts`:

- The generated migration is imported.
- The `migrations` array points `up`, `down`, and `name` at the generated migration.
- The migration `name` matches the generated filename without extension.

For the `create_regattas_collection` example, the expected changes were:

- Create `regattas`.
- Create `enum_regattas_country` and `enum_regattas_cup`.
- Add `payload_locked_documents_rels.regattas_id`.
- Add indexes for `regattas.updated_at`, `regattas.created_at`, and the lock relation.
- Add the lock relation foreign key.

If the diff contains unrelated changes, inspect other Payload config or collection edits before keeping the migration.

## Step 4 - Handle Manual SQL Only When Needed

Use generated migrations by default. If Payload cannot represent the required database object, create or edit a migration intentionally and keep the SQL minimal.

Common examples:

- Custom Postgres functions or triggers
- Expression or partial indexes not represented by Payload config
- Data backfills or data transformations
- Database objects outside Payload's schema model

For manual SQL:

- Keep `up()` and `down()` symmetrical.
- Add only the custom SQL required for the change.
- Leave Payload collection/global config as the source of truth for representable schema.
- Add a concise code comment near the relevant config only if the database object cannot be discovered from Payload config.

## Step 5 - Stop Here. Do Not Run the Migration

Never run `npm run migrate` or any migration execution command automatically. The developer runs migrations manually at the right time after coordinating database state.

Do not suggest running the migration as a verification step. Leave the generated files ready and report what was created and reviewed.

In the final response, always include the manual run command in a copy-ready fenced block:

```bash
npm run migrate
```

Label it as a manual command for the developer to run when ready.

## Quick Reference

| Command                                      | Purpose                                  |
| -------------------------------------------- | ---------------------------------------- |
| `npm run migrate:create <migration_name>`    | Generate a Payload migration             |
| `npm run payload -- migrate:create <name>`   | Underlying Payload command               |
| `npm run migrate`                            | Run manually only - never automated      |
| `npm run payload -- migrate:status`          | Inspect migration state when requested   |

## Key Paths

- Payload config: `src/payload.config.ts`
- Collections: `src/collections/`
- Migrations: `src/migrations/`
- Migration registry: `src/migrations/index.ts`
- Generated Payload types: `src/payload-types.ts`

