Help us improve
Share bugs, ideas, or general feedback.
From migration-patterns-plugin
Guides dual write migration pattern for safely transitioning between data stores during database migrations, backend switches, schema changes, or multi-system writes.
npx claudepluginhub laurigates/claude-plugins --plugin migration-patterns-pluginHow this skill is triggered — by the user, by Claude, or both
Slash command
/migration-patterns-plugin:dual-writeopusThis skill is limited to the following tools:
The summary Claude sees in its skill listing — used to decide when to auto-load this skill
Dual write keeps two data stores in sync by writing to both the old and new system on every mutation. This enables gradual migration with rollback safety.
Guides schema and data migrations across engines with tools like Flyway, Liquibase, Alembic, Prisma Migrate. Covers zero-downtime patterns (expand-contract), cross-engine (MySQL→PG), CDC (Debezium). Use for schema changes or DB migrations.
Guides safe database schema changes and code migrations with zero-downtime strategies including backfills, dual-writes, feature flags, and Strangler Fig pattern.
Provides strategies for zero-downtime deployments, expand-contract schema changes, database migrations, and framework migrations. Use when planning safe system migrations.
Share bugs, ideas, or general feedback.
Dual write keeps two data stores in sync by writing to both the old and new system on every mutation. This enables gradual migration with rollback safety.
| Use this skill when... | Use shadow-mode instead when... |
|---|---|
| Migrating between databases or schemas | Validating read-path behavior under real traffic |
| Switching storage backends (SQL to NoSQL, etc.) | Testing a new service without writing to it |
| Need both systems to stay authoritative during transition | Only need to compare responses, not persist data |
| Planning zero-downtime data migrations | Mirroring traffic to a staging environment |
| Reviewing code that writes to multiple data stores | Evaluating performance of a replacement system |
| Phase | Primary reads | Primary writes | Secondary writes | Duration |
|---|---|---|---|---|
| 1. Prepare | Old | Old | None | Setup |
| 2. Dual write | Old | Old + New | New (async or sync) | Migration window |
| 3. Backfill | Old | Old + New | New | Until parity |
| 4. Shadow read | Old + New (compare) | Old + New | New | Validation |
| 5. Cutover | New | New | Old (optional) | Transition |
| 6. Cleanup | New | New | None | Final |
| Strategy | Consistency | Latency impact | Failure mode |
|---|---|---|---|
| Synchronous | Strong | Higher (2x write) | Fail if either store fails |
| Async secondary | Eventual | Minimal | Secondary may lag |
| Outbox pattern | Eventual | Minimal | Requires message broker |
| Change data capture | Eventual | None (DB-level) | Requires CDC infrastructure |
Client Request
│
▼
┌─────────────┐
│ Application │
│ Layer │
└──────┬──────┘
│ write(data)
▼
┌─────────────┐
│ Dual Write │
│ Adapter │
├──────┬──────┤
│ │ │
▼ │ ▼
Old DB │ New DB
│
Compare on
read (optional)
| Component | Responsibility |
|---|---|
| Write adapter | Routes writes to both stores, handles failures |
| Read comparator | Reads from both, logs discrepancies, returns primary |
| Backfill job | Copies historical data from old to new store |
| Reconciliation | Detects and resolves drift between stores |
| Feature flags | Controls which phase is active per entity/tenant |
The write adapter wraps both stores behind a single interface:
During the shadow read phase:
| Failure scenario | Response | Recovery |
|---|---|---|
| Secondary write fails | Log, continue, enqueue retry | Async retry with backoff |
| Primary write fails | Fail the request (do not write to secondary) | Standard error handling |
| Both fail | Fail the request | Standard error handling |
| Secondary write timeout | Log, continue | Async verification and repair |
| Inconsistency detected | Log with full context | Manual or automated reconciliation |
| Metric | Threshold | How to measure |
|---|---|---|
| Read comparison match rate | > 99.9% | Shadow read comparison logs |
| Backfill completion | 100% | Backfill progress tracker |
| Secondary write success rate | > 99.95% | Write adapter metrics |
| P99 latency impact | < 20% increase | Application metrics |
| Reconciliation gap | 0 unresolved | Reconciliation job output |
| Pitfall | Mitigation |
|---|---|
| Ordering issues between stores | Use idempotent writes, include version/timestamp |
| Transaction boundaries differ | Design writes to be independently valid |
| Schema mismatch between stores | Map fields explicitly, handle nullability differences |
| Backfill conflicts with live writes | Live dual writes take precedence over backfill |
| Performance degradation | Start with async secondary writes |
| Partial failures leave inconsistency | Reconciliation job as safety net |
| Forgetting to dual-write in all code paths | Centralize through write adapter, audit call sites |
| Phase | Rollback action | Data impact |
|---|---|---|
| Dual write | Stop writing to new store | No data loss |
| Shadow read | Stop comparing reads | No data loss |
| Cutover (reads) | Switch reads back to old | No data loss if still dual-writing |
| Cutover (writes) | Reverse write order | May need reconciliation |
| Cleanup | Cannot rollback | Old store decommissioned |
| Context | Approach |
|---|---|
| Code review | Check that all write paths go through the dual-write adapter |
| Architecture review | Verify failure handling, rollback plan, and cutover criteria |
| Implementation | Start with write adapter + async secondary, add comparison later |
| Testing | Simulate secondary failures, verify primary is unaffected |
| Term | Definition |
|---|---|
| Primary store | The authoritative data store (old system during migration) |
| Secondary store | The new data store being migrated to |
| Backfill | Copying historical data from primary to secondary |
| Reconciliation | Detecting and repairing differences between stores |
| Cutover | Switching the primary designation from old to new |
| Match rate | Percentage of shadow reads that return identical results |
| Write adapter | Abstraction layer that routes writes to both stores |