К основному содержанию
скилл CX Codex

convex-migrations — скилл для Claude Code: миграции Convex

Проводит изменение схемы Convex через шесть шагов: сделать поле необязательным, залить данные батчами, переключить валидатор, подчистить. Пригодится, когда npx convex dev падает на существующих документах.

Установить в Claude Code · Через Skills CLI (Vercel) Все способы и платформы ↓
npx skills add waynesutton/builder-skills --skill convex-migrations -a claude-code
Открыть на GitHub

Что делает convex-migrations

Convex не хранит файлы миграций и не имеет команды migrate. npx convex dev проталкивает схему и проверяет по ней каждый существующий документ, но сами данные не преобразует. Скилл задаёт порядок: сначала меняем данные, потом ужесточаем валидатор. Схема должна описывать то, что лежит в базе сейчас, а не то, что вы хотите там видеть.

Последовательность из шести шагов: пометить поле как v.optional в convex/schema.ts, задеплоить, обновить читателей и писателей, залить существующие документы батчами, переключить валидатор в финальный вид и задеплоить снова. Шаги 1 и 2 обязательно выкатываются до старта бэкфилла — иначе новые записи продолжат приходить в старой форме, пока идёт заливка. Внутри есть готовый internalMutation с paginate, который патчит только нужные документы и перезапускает себя по курсору: каждый батч — отдельная транзакция, поэтому большая таблица не упирается в лимит функции. Запуск из CLI: npx convex run migrations:backfillAvatarUrl '{"cursor": null}'.

Если миграций в проекте будет больше одной-двух, скилл советует компонент @convex-dev/migrations: он добавляет сохранение прогресса, проверку статуса, dry run, отмену и запуск нескольких миграций в заданном порядке. Для разового бэкфилла небольшой таблицы хватит рукописной мутации. Не передавайте { schemaValidation: false } в defineSchema, чтобы протолкнуть деплой: ошибка не исчезнет, а переедет в ваши запросы.

Какие задачи решает

  • добавить обязательное поле в таблицу, где уже есть строки
  • переименовать поле или сменить его тип без падения деплоя
  • разбить одну таблицу на две или слить две в одну
  • починить Schema validation failed после правки схемы
  • залить больше строк, чем тянет одна мутация

Примеры запросов агенту

  • Помоги переименовать поле avatarUrl в imageUrl в таблице users без даунтайма
  • npx convex dev падает с Schema validation failed на таблице users — разбери ошибку и предложи миграцию
  • Настрой @convex-dev/migrations и сделай dry run для бэкфилла поля role

Как установить convex-migrations

1Через Skills CLI (Vercel)

npx skills add waynesutton/builder-skills --skill convex-migrations -a claude-code

2Вручную: положить файлы

~/.claude/skills/convex-migrations/SKILL.md

Папка скилла целиком; для одного проекта — .claude/skills/convex-migrations/

По шагам, с командами для каждой платформы: Как установить скилл в Claude Code: пять способов

Вопросы о convex-migrations

Как установить convex-migrations в Claude?

Выполните npx skills add waynesutton/builder-skills --skill convex-migrations -a claude-code. Скилл окажется в ~/.claude/skills/convex-migrations/SKILL.md.

Что делает convex-migrations?

Ведёт изменение живой схемы Convex по безопасной последовательности: необязательное поле, деплой, батчевый бэкфилл, финальный валидатор, уборка. Отдельно объясняет, как читать ошибку валидации при деплое.

Когда нужен компонент @convex-dev/migrations, а когда хватит рукописной мутации?

Компонент стоит брать, если миграций будет несколько, нужен dry run или проверка, завершилась ли миграция в продакшене. Разовый бэкфилл небольшой таблицы закрывает обычная internalMutation с paginate.

Исходный текст

SKILL.md · Apache-2.0
---
name: convex-migrations
description: Changes a live Convex schema without downtime: make a field optional, backfill in batches, flip the validator, then clean up. Uses the @convex-dev/migrations component where it fits. Use when renaming or removing a field, changing a type, splitting a table, or when deploy fails with a schema validation error on existing documents.
---

# Convex migrations

Produces a schema change plus a batched backfill that keeps every deploy green. The one rule: the schema must describe the documents that exist right now, not the documents you want. Change the data first, then tighten the validator.

Convex has no migration files or `migrate` command. `npx convex dev` pushes the schema and validates every existing document against it. Existing data is never transformed for you.

## When to reach for this

- Adding a field that should be required, but the table already has rows
- Renaming a field, changing its type, or removing it
- Splitting one table into two or merging two into one
- `npx convex dev` fails with `Schema validation failed` after a schema edit
- A backfill needs to touch more rows than one mutation can handle

For step by step recipes (rename, change type, split, merge, add required, remove) open [references/migration-patterns.md](references/migration-patterns.md). For installing and running `@convex-dev/migrations` open [references/migrations-component.md](references/migrations-component.md).

## The safe sequence

Every migration follows the same six steps. Skipping one is how deploys break.

1. Make the field optional in `convex/schema.ts` (or add the new field as `v.optional`).
2. Deploy with `npx convex dev`. Update readers to handle `undefined` and writers to set the new shape.
3. Backfill existing documents in batches with an internal mutation or the migrations component.
4. Flip the validator to its final shape (`v.string()` instead of `v.optional(v.string())`, or drop the old field).
5. Deploy again. Validation now passes because every document already matches.
6. Clean up: delete fallback code, remove the backfill function, drop stale indexes.

Steps 1 and 2 must ship before step 3 starts. Otherwise new writes keep producing old shaped documents while the backfill runs.

## Hand rolled batched backfill

One `internalMutation` that pages through the table with `paginate`, patches only documents that still need it, then reschedules itself with the continue cursor. Each batch is its own transaction, so a large table never hits the per function limit.

```typescript
// convex/migrations.ts
import { internalMutation } from "./_generated/server";
import { internal } from "./_generated/api";
import { v } from "convex/values";

const BATCH_SIZE = 100;

export const backfillAvatarUrl = internalMutation({
  args: { cursor: v.union(v.string(), v.null()) },
  returns: v.null(),
  handler: async (ctx, args) => {
    const result = await ctx.db
      .query("users")
      .paginate({ numItems: BATCH_SIZE, cursor: args.cursor });

    for (const user of result.page) {
      // Idempotent: skip documents that already have the field
      if (user.avatarUrl === undefined) {
        await ctx.db.patch(user._id, {
          avatarUrl: defaultAvatar(user.name),
        });
      }
    }

    // Reschedule with the cursor until the table is exhausted
    if (!result.isDone) {
      await ctx.scheduler.runAfter(0, internal.migrations.backfillAvatarUrl, {
        cursor: result.continueCursor,
      });
    }
    return null;
  },
});

function defaultAvatar(name: string): string {
  return `https://api.dicebear.com/7.x/initials/svg?seed=${encodeURIComponent(name)}`;
}
```

Start it from the CLI against the dev deployment:

```bash
npx convex run migrations:backfillAvatarUrl '{"cursor": null}'
```

Keep the mutation idempotent. Re running it after a partial failure must be safe. Use `internalMutation`, never a public `mutation`, so it cannot be called from a client. Use `ctx.db.patch` for adding or changing fields and `ctx.db.patch(id, { field: undefined })` to remove one.

## When to use the component instead

`@convex-dev/migrations` wraps the pattern above and adds what the hand rolled version lacks: persisted progress per migration, status checks, dry runs, cancel, and ordered runs of several migrations. Reach for it when:

- The project will run more than one or two migrations over its life
- You need to know whether a migration already completed in production
- You want a dry run before touching real data
- Several migrations must run in a fixed order

Minimal setup:

```typescript
// convex/convex.config.ts
import { defineApp } from "convex/server";
import migrations from "@convex-dev/migrations/convex.config.js";

const app = defineApp();
app.use(migrations);
export default app;
```

```typescript
// convex/migrations.ts
import { Migrations } from "@convex-dev/migrations";
import { components } from "./_generated/api";
import { DataModel } from "./_generated/dataModel";

export const migrations = new Migrations<DataModel>(components.migrations);

export const addDefaultRole = migrations.define({
  table: "users",
  migrateOne: async (ctx, user) => {
    if (user.role === undefined) {
      await ctx.db.patch(user._id, { role: "user" });
    }
  },
});
```

```bash
npx convex run migrations:addDefaultRole '{"dryRun": true}'
npx convex run migrations:addDefaultRole
```

A one off backfill on a small table does not need the component. The hand rolled mutation is fine.

## Reading the deploy time schema error

When a schema push fails, `npx convex dev` prints the table, one offending document id, and the field that does not match:

```
Schema validation failed
Document with ID "j57abc..." in table "users" does not match the schema:
Object is missing the required field `avatarUrl`.
Consider wrapping the field validator in `v.optional(...)` if this is expected.
```

Read it as: existing data in `users` predates the field. The fix is never to delete the document. Wrap the field in `v.optional`, deploy, backfill, then remove the `v.optional`. If the error says the field has the wrong type (for example `string` where `number` is expected), widen the validator to `v.union(v.string(), v.number())`, backfill the conversion, then narrow it.

Do not pass `{ schemaValidation: false }` to `defineSchema` to make the push succeed. It hides the mismatch and moves the failure into your queries.

## Common mistakes

| Mistake | Why it breaks | Do instead |
| --- | --- | --- |
| Add a required field in one deploy | Existing documents fail validation, push is rejected | Add as `v.optional`, backfill, then require |
| Start the backfill before deploying the new writers | New rows keep arriving in the old shape | Deploy schema and code first, backfill second |
| One mutation that `.collect()`s the whole table | Hits the transaction size and time limits | Page with `paginate` and reschedule per batch |
| Backfill with a public `mutation` | Anyone can call it and re run it | `internalMutation` or `migrations.define` |
| Non idempotent patch | Re running after a failure double applies | Check the field before patching |
| Removing the old field before readers stop using it | Fallback code reads `undefined` | Switch readers, then remove |
| Using `.filter()` to find unmigrated rows | Full scan on every batch | Paginate the whole table or use `customRange` with an index |
| Turning off `schemaValidation` to pass the deploy | Bad data reaches queries at runtime | Fix the data, keep validation on |
| Running a backfill against production first | No way to catch a wrong conversion | Run on dev, then `--prod` |

## Checklist

- [ ] New or changed field is `v.optional` (or a widened `v.union`) in the first deploy
- [ ] Readers handle `undefined` and writers produce the new shape before the backfill starts
- [ ] Backfill is an `internalMutation` or `migrations.define`, never public
- [ ] Backfill pages with `paginate` and reschedules via `ctx.scheduler.runAfter(0, internal....)`
- [ ] Each patch is guarded so re running is safe
- [ ] Backfill ran to completion on dev before touching prod
- [ ] Validator flipped to its final shape and deployed without a validation error
- [ ] Fallback code, old field, and backfill function removed
- [ ] Indexes that referenced the old field are dropped or renamed

## Docs

- https://docs.convex.dev/llms.txt
- https://docs.convex.dev/database/schemas
- https://docs.convex.dev/database/pagination
- https://www.convex.dev/components/migrations
- https://stack.convex.dev/migrating-data-with-mutations

© waynesutton · Apache-2.0 · waynesutton/builder-skills

Похожие скиллы

Все скиллы по теме «Данные и базы» →
convex-migrate convex Скилл проводит миграцию схемы и бэкфилл данных в развёрнутом приложении Convex через @convex-dev/migrations. Пригодится, когда меняешь схему на живом приложении. CX Codex +1 36 100установок convex-migrate-rehearse convex Прогоняет изменение схемы и бэкфилл на превью-деплое с продовым снапшотом, а потом переносит проверенную миграцию в прод. CX Codex +1 35 900установок convex Mindrally Задаёт агенту правила работы с Convex: запросы, мутации, actions, индексы и файлы. Пригодится, когда бэкенд на Convex уже выбран. CX Codex +1 651установок surrealkit surrealdb Скилл учит агента работать с SurrealKit — CLI для синхронизации схем SurrealDB, планирования миграций и генерации типов. CX Codex +1 400установок migration JuliusBrussee Скилл задаёт правила безопасных миграций схем, данных и API с обязательным откатом. Пригодится при изменениях, где нельзя терять данные или ломать совместимость. CX Codex +1 103 900установок database-migrations affaan-m Скилл описывает безопасные и обратимые миграции схемы: expand-contract, индексы CONCURRENTLY, батч-бэкфиллы и рабочие процессы для PostgreSQL, Prisma, Drizzle, Kysely, Django и golang-migrate. CX Codex +1 5 200установок

Из того же набора14

convex-realtime Скилл объясняет, как связать фронтенд с подписками Convex: useQuery, оптимистичные обновления, живая пагинация и борьба с лишними ререндерами. CX Codex +1 2 900установок convex-cron-jobs Настраивает периодические задачи в convex/crons.ts и отложенный запуск через ctx.scheduler. Помогает разбить мутации на пачки и отладить фоновые очереди. CX Codex +1 2 800установок convex-security-check Проверяет Convex-бэкенд перед слиянием изменений: публичные функции, авторизацию, владение данными, валидацию и секреты. CX Codex +1 2 700установок convex-http-actions Добавляет HTTP-эндпоинты в convex/http.ts: приём вебхуков с проверкой подписи, REST-маршруты, CORS, стриминг и загрузка файлов. CX Codex +1 2 700установок convex-file-storage Настраивает хранение файлов в Convex: загрузку через временные URL, сохранение blob в actions и раздачу через getUrl. Пригодится при работе с документами и пользовательскими картинками. CX Codex +1 2 600установок convex-agents Скилл учит ИИ строить агентов на компоненте @convex-dev/agent. Пригодится для чатов с историей тредов, RAG и вызова мутаций Convex как инструментов. CX Codex +1 1 500установок convex-security-audit Скилл проводит полный разбор безопасности приложения на Convex и выдаёт письменный отчёт по найденным проблемам. Пригодится перед запуском или после инцидента. CX Codex +1 1 500установок avoid-feature-creep Удерживает правки агента строго в границах задачи. Выносит попутный рефакторинг и лишние фичи в отдельный список предложений вместо diff. CX Codex +1 1 300установок

Спонсоры проекта

Компании, которые помогают держать аналитику открытой