| name | sow |
| description | Generate safe test databases from production Postgres. Create isolated database branches with sanitized data for testing migrations, running test suites, and letting coding agents work with production-like data without PII exposure. Requires Docker. |
Database Testing with sow
Core Workflow
Every database testing task follows this pattern:
- Connect:
sow connect <postgres-url> (one-time, creates sanitized snapshot)
- Branch:
sow branch create <n> (isolated Postgres in ~5s)
- Use: Connect your app/tests to the branch URL
- Inspect:
sow branch diff <n> (see what changed)
- Clean up:
sow branch delete <n>
Quick Start
Setup (one time per database)
sow connect
sow connect --full
sow connect postgresql://user:pass@host:5432/mydb
sow connect postgresql://user:pass@host:5432/mydb --full
Use --full when tests fail due to missing data or broken relationships. Default sampling is faster but may miss some rows.
Create a branch to test on
sow branch create my-feature
Work with it
sow branch run my-feature -- <project's dev command>
To find the right command, check the project's package.json scripts, Makefile, docker-compose.yml, or README.
See what changed
sow branch diff my-feature
Clean up
sow branch delete my-feature
Running an App with a Branch
sow branch run injects DATABASE_URL, SUPABASE_URL, and all other branch env vars into whatever command you pass after --.
sow branch create dev
sow branch run dev -- <project's dev command>
sow branch run dev -- <project's test command>
sow branch run dev -- <project's migration command>
Important: The command after -- is project-specific. Check package.json scripts, Makefile, or the project's README to find the correct command. Don't assume any particular package manager or framework.
Discover What's in the Branch
After creating a branch, use these commands to discover what's available:
sow branch env dev
sow branch users dev
sow branch tables dev
sow branch sample dev users --limit 3
All discovery commands support --json for structured agent consumption:
sow branch env dev --json
sow branch users dev --json
sow branch tables dev --json
sow branch sample dev users --json --limit 5
Common Patterns
Migration Testing
sow branch create migration-test
sow branch run migration-test -- npx prisma migrate dev
sow branch diff migration-test
sow branch delete migration-test
Iterative Development with Save/Load
sow branch create dev
sow branch save dev after-change-a
sow branch load dev after-change-a
sow branch delete dev
Test Suite with Clean State
sow branch create tests
sow branch run tests -- <your-test-command>
sow branch reset tests
sow branch run tests -- <your-test-command>
sow branch delete tests
E2E Testing with Browser Agent
sow branch create e2e
sow branch run e2e -- <your-dev-command> &
sow branch users e2e
sow branch diff e2e
sow branch delete e2e
Specific Test Scenarios via Exec
sow branch create scenario
sow branch exec scenario --sql "UPDATE users SET plan = 'expired' WHERE id = 1"
sow branch reset scenario
sow branch exec scenario --sql "INSERT INTO carts (user_id, items) VALUES (1, 3)"
sow branch delete scenario
CI/CD Pipeline
sow connect $DATABASE_URL --quiet
BRANCH_URL=$(sow branch create ci-$CI_COMMIT_SHA --quiet)
DATABASE_URL=$BRANCH_URL npm test
sow branch delete ci-$CI_COMMIT_SHA
Write Env Vars to a File
sow branch env dev --env-file .env.local
Key Behaviors
- Branches are fully isolated -- changes don't affect other branches or production
- Data looks like production but all PII is automatically replaced with realistic fakes
sow branch run injects env vars -- always use it instead of manually setting DATABASE_URL, SUPABASE_URL, etc.
sow branch users gives test credentials -- all test accounts use password password123
- Check the project's own docs (package.json, Makefile, README) to find the right dev/start/test commands
- Deterministic -- same seed (default: 42) produces identical output every time
- Docker or Supabase -- auto-detects if
supabase start is running, otherwise uses Docker
- Ports 54320-54399 -- sow auto-assigns free ports in this range
- Credentials are always
sow/sow -- test data doesn't need security
sow branch reset takes ~1s -- the sampled DB is small (MBs, not GBs)
- Read-only access to production -- sow never writes to your source database
Troubleshooting
psycopg2 / asyncpg / SQLAlchemy dialect errors
sow branch run sets DATABASE_URL=postgresql://... (standard format). If the project uses SQLAlchemy with create_async_engine, it needs postgresql+asyncpg:// instead. sow also sets DATABASE_URL_ASYNC with this format. Fix: update the project's database config to use DATABASE_URL_ASYNC, or add URL normalization:
url = os.environ["DATABASE_URL"].replace("postgresql://", "postgresql+asyncpg://")
Connection refused
The branch may not be running. Check with sow branch list and start it with sow branch start <name>.
Missing data / broken foreign keys / tests failing
The default mode samples ~200 rows per table. If tests fail because of missing related data, re-connect with full copy:
sow connect --full
sow branch delete <name>
sow branch create <name>
No tables found / 0 rows
The source database may have no tables in the public schema, or the snapshot was taken before migrations ran. Re-run sow connect after running migrations on the source DB.
Auth / login not working
Use sow branch users <name> to get the exact test emails. Password is always password123. Make sure the app's auth is pointing at the branch's Supabase URL (check sow branch env <name>).
Docker not running
sow needs Docker for standalone branches. Start Docker Desktop, or use supabase start for Supabase-based branches (auto-detected).
When NOT to Use sow
- Load testing (sampled DB is too small for realistic load)
- When you need real PII (sow replaces everything it detects)
- Performance benchmarks (Docker adds overhead vs native Postgres)
- When you need the complete dataset (sow samples ~50 rows/table by default)
Deep-Dive References
Ready-to-Use Templates