dual-write
SKILL.md
Dual Write Migration Pattern
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.
When to Use This Skill
| 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 |
Core Concepts
Migration Phases
| 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 |
Write Strategies
| 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 |
Implementation Architecture
Synchronous Dual Write
Client Request
│
▼
┌─────────────┐
│ Application │
│ Layer │
└──────┬──────┘
│ write(data)
▼
┌─────────────┐
│ Dual Write │
│ Adapter │
├──────┬──────┤
│ │ │
▼ │ ▼
Old DB │ New DB
│
Compare on
read (optional)
Key Components
| 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 |
Implementation Patterns
Write Adapter Pattern
The write adapter wraps both stores behind a single interface:
- Accept the write request
- Write to the primary (old) store first
- Write to the secondary (new) store
- If secondary fails: log the failure, enqueue for retry, do not fail the request
- Return the primary store's result to the caller
Read Comparison Pattern
During the shadow read phase:
- Read from the primary (old) store — this is the authoritative response
- Read from the secondary (new) store asynchronously
- Compare results field by field
- Log discrepancies with context (entity ID, field, old value, new value)
- Return the primary store's result
- Track comparison metrics (match rate, common divergence fields)
Backfill Strategy
- Snapshot the old store at a known point in time
- Begin dual writes for all new mutations
- Copy historical records in batches (oldest first or by priority)
- Track backfill progress per entity type
- Reconcile records modified during backfill (dual write wins over backfill)
Failure Handling
| 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 |
Consistency Guarantees
- Primary store is always the source of truth until cutover
- Secondary store may lag during async dual write
- Reconciliation jobs detect and repair drift
- Cutover only happens when match rate reaches threshold (e.g., 99.9%)
Cutover Decision Criteria
| 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 |
Common Pitfalls
| 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 |
Rollback Plan
| 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 |
Monitoring Checklist
- Write success rate per store
- Write latency per store (P50, P95, P99)
- Read comparison match rate
- Backfill progress percentage
- Reconciliation queue depth
- Error rate by failure type
- Feature flag state per tenant/entity
Agentic Optimizations
| 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 |
Quick Reference
| 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 |
Weekly Installs
26
Repository
laurigates/clau…-pluginsGitHub Stars
14
First Seen
Feb 27, 2026
Security Audits
Installed on
cline26
github-copilot26
codex26
kimi-cli26
gemini-cli26
cursor26