Schema diff between connections
Pro tier. Tools → Schema diff opens a side-by-side comparison between two open connections.
Pick the sides
Section titled “Pick the sides”The dialog has two pickers — Source and Target, each showing your active sessions. Same connection on both sides (e.g. dev DB twice) is allowed; same engine on both sides isn’t required (PG → MySQL diffs work, with type-mapping hints).
What’s compared
Section titled “What’s compared”By default, everything:
- Tables — present in source vs target, plus per-table:
- Columns: name, type, NULL, default, identity / AUTO_INCREMENT
- Primary key (composition + order)
- Foreign keys (target column, ON DELETE / UPDATE actions)
- Indexes (column composition, uniqueness, partial WHERE clauses)
- Triggers (full body)
- Comments
- Views — definition + materialised flag
- Sequences (PG) — current value, increment, min/max
- Functions / procedures — full body (with normalisation for whitespace + comments so cosmetic-only diffs are filtered)
- Schemas / databases — character set + collation
- Optional: data — per-table row count + sample-row diff (locked decision: schema diff is full scope by default, with a schema-only toggle)
Output
Section titled “Output”The diff renders as a tree:
✗ users (in source, missing in target) + columns: subscription_tier, subscribed_at✓ orders (matches)~ products (differs) ~ column: price NUMERIC(10,2) → DECIMAL(12,2) ~ index: idx_products_active NEW: WHERE archived_at IS NULL - column: legacy_sku (in source, missing in target)+ stripe_events (in target, missing in source)Click any difference to see the full proposed ALTER statement.
Generate ALTER statements
Section titled “Generate ALTER statements”Below the tree: Apply changes → opens a SQL preview with one ALTER / CREATE / DROP per difference, in dependency-safe order.
You can:
- Uncheck individual differences to skip them in this run
- Edit the SQL inline (e.g. tweak the type cast for a wide column)
- Pick the target to apply against (defaults to “Target”, but can go to a third connection for migration-staging workflows)
- Save the SQL as a migration — emits two
*.up.sql/*.down.sqlfiles into your project’smigrations/folder
Cross-engine diffs
Section titled “Cross-engine diffs”Diffing PG → MySQL or MySQL → SQLite shows type-mapping warnings:
~ column: created_at TIMESTAMPTZ → DATETIME ⚠ MySQL DATETIME has no timezone — UTC offset will be lost Suggested: store offset separately, or use TIMESTAMPThe diff is informational by default — you choose whether to
proceed. If the target engine genuinely can’t represent the source’s
type (PG JSONB → MariaDB without JSON support), the row is
flagged red with no auto-suggested ALTER.
Limits
Section titled “Limits”- Very wide tables (>500 columns) — diff works, just slow (~5–10s for full comparison). Use the “schema-only” toggle to skip data-side comparisons for an instant result.
- Materialised views with circular dependencies — Quay flags them but doesn’t yet auto-resolve order. You may need to manually edit the apply SQL to drop + recreate in the right sequence.
- Per-row data diff — currently a sample (first 100 rows) + count comparison. A full row-by-row diff for a 10M-row table is expensive; that path is gated behind an explicit “full data diff” button with size warning.
Common patterns
Section titled “Common patterns”- Pre-deployment check: diff dev → prod before pushing a migration. Catches “I forgot to add the index in the deploy script” the day before it goes live.
- Drift detection: weekly diff between two prod replicas to catch out-of-band changes (someone hand-edited the DB).
- Migration generation: diff “what I have” → “what I want” (across two test DBs), generate the ALTER, save as a migration.