Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
Plan and execute safe Convex schema migrations: add fields, change types, split/merge tables, backfill data.
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
SKILL.md
1---2name: convex-migration-helper3description:4Plans Convex schema and data migrations with widen-migrate-narrow and5@convex-dev/migrations. Use for breaking schema changes, backfills, table6reshaping, or zero-downtime rollouts.7---89# Convex Migration Helper1011Safely migrate Convex schemas and data when making breaking changes.1213## When to Use1415- Adding new required fields to existing tables16- Changing field types or structure17- Splitting or merging tables18- Renaming or deleting fields19- Migrating from nested to relational data2021## When Not to Use2223- Greenfield schema with no existing data in production or dev24- Adding optional fields that do not need backfilling25- Adding new tables with no existing data to migrate26- Adding or removing indexes with no correctness concern27- Questions about Convex schema design without a migration need2829## Key Concepts3031### Schema Validation Drives the Workflow3233Convex will not let you deploy a schema that does not match the data at rest.34This is the fundamental constraint that shapes every migration:3536- You cannot add a required field if existing documents don't have it37- You cannot change a field's type if existing documents have the old type38- You cannot remove a field from the schema if existing documents still have it3940This means migrations follow a predictable pattern: **widen the schema, migrate41the data, narrow the schema**.4243### Online Migrations4445Convex migrations run online, meaning the app continues serving requests while46data is updated asynchronously in batches. During the migration window, your47code must handle both old and new data formats.4849### Prefer New Fields Over Changing Types5051When changing the shape of data, create a new field rather than modifying an52existing one. This makes the transition safer and easier to roll back.5354### Don't Delete Data5556Unless you are certain, prefer deprecating fields over deleting them. Mark the57field as `v.optional` and add a code comment explaining it is deprecated and why58it existed.5960## Safe Changes (No Migration Needed)6162### Adding Optional Field6364```typescript65// Before66users: defineTable({67name: v.string(),68});6970// After - safe, new field is optional71users: defineTable({72name: v.string(),73bio: v.optional(v.string()),74});75```7677### Adding New Table7879```typescript80posts: defineTable({81userId: v.id("users"),82title: v.string(),83}).index("by_user", ["userId"]);84```8586### Adding Index8788```typescript89users: defineTable({90name: v.string(),91email: v.string(),92}).index("by_email", ["email"]);93```9495## Breaking Changes: The Deployment Workflow9697Every breaking migration follows the same multi-deploy pattern:9899**Deploy 1 - Widen the schema:**1001011. Update schema to allow both old and new formats (e.g., add optional new102field)1032. Update code to handle both formats when reading1043. Update code to write the new format for new documents1054. Deploy106107**Between deploys - Migrate data:**1081095. Run migration to backfill existing documents1106. Verify all documents are migrated111112**Deploy 2 - Narrow the schema:**1131147. Update schema to require the new format only1158. Remove code that handles the old format1169. Deploy117118## Using the Migrations Component119120For any non-trivial migration, use the121[`@convex-dev/migrations`](https://www.convex.dev/components/migrations)122component. It handles batching, cursor-based pagination, state tracking, resume123from failure, dry runs, and progress monitoring.124125See `references/migrations-component.md` for installation, setup, defining and126running migrations, dry runs, status monitoring, and configuration options.127128## Common Migration Patterns129130See `references/migration-patterns.md` for complete patterns with code examples131covering:132133- Adding a required field134- Deleting a field135- Changing a field type136- Splitting nested data into a separate table137- Cleaning up orphaned documents138- Zero-downtime strategies (dual write, dual read)139- Small table shortcut (single internalMutation without the component)140- Verifying a migration is complete141142## Common Pitfalls1431441. **Making a field required before migrating data**: Convex rejects the deploy145because existing documents lack the field. Always widen the schema first.1462. **Using `.collect()` on large tables**: Hits transaction limits or causes147timeouts. Use the migrations component for proper batched pagination.148`.collect()` is only safe for tables you know are small.1493. **Not writing the new format before migrating**: Documents created during the150migration window will be missed, leaving unmigrated data after the migration151"completes."1524. **Skipping the dry run**: Use `dryRun: true` to validate migration logic153before committing changes to production data. Catches bugs before they touch154real documents.1555. **Deleting fields prematurely**: Prefer deprecating with `v.optional` and a156comment. Only delete after you are confident the data is no longer needed and157no code references it.1586. **Using crons for migration batches**: The migrations component handles159batching via recursive scheduling internally. Crons require manual cleanup160and an extra deploy to remove.161162## Migration Checklist163164- [ ] Identify the breaking change and plan the multi-deploy workflow165- [ ] Update schema to allow both old and new formats166- [ ] Update code to handle both formats when reading167- [ ] Update code to write the new format for new documents168- [ ] Deploy widened schema and updated code169- [ ] Define migration using the `@convex-dev/migrations` component170- [ ] Test with `dryRun: true`171- [ ] Run migration and monitor status172- [ ] Verify all documents are migrated173- [ ] Update schema to require new format only174- [ ] Clean up code that handled old format175- [ ] Deploy final schema and code176- [ ] Remove migration code once confirmed stable177