How a migration runs, end to end.
You describe the move. Morph analyzes its shape, prices it with a fixed one-time quote, and generates every artifact you need to execute — while you stay fully in control of when and how it runs.
Nothing touches your data
Morph works from your description, never a live connection.
Pricing you can audit
The model proposes; the server computes. Same shape, same price.
Rollback armed throughout
Every plan ships with explicit triggers and a fast path back.
Four phases from idea to execution.
Each phase produces something concrete — a classification, a quote, a plan, and finally the artifacts themselves.
Describe the move
Pick source and target engines and versions, give a rough data volume, table count and row estimate, and set your downtime tolerance. No credentials, no agent, no production access.
The AI analyzes
Morph reads the shape of your migration, classifies it — homogeneous, cross-engine or cross-paradigm — scores complexity, and surfaces the specific risks: dialect drift, paradigm remodeling, large transfer windows, integrity on load.
A fixed quote, then pay once
Complexity becomes a single deterministic price — computed server-side, shown before you commit. One payment per migration unlocks generation. No subscription, nothing metered while you run it.
Morph generates everything
Within moments you have five execution-ready artifacts plus a per-migration AI chat to walk you through any of them. You run the migration on your own schedule, fully in control.
Five artifacts. Real files, not a report.
Payment unlocks the complete set needed to execute and de-risk the migration. Here is a sample of each, drawn from a MySQL → PostgreSQL move.
Target schema & type map
Faithful DDL for the target with a verified per-column type map. Engine-specific constructs are translated, not guessed — AUTO_INCREMENT becomes a generated identity, TINYINT(1) becomes boolean, and DATETIME lands as timestamptz.
-- MySQL → PostgreSQL · verified type map
-- tinyint(1) → boolean · datetime → timestamptz
CREATE TABLE orders (
id bigint GENERATED ALWAYS AS IDENTITY,
customer_id bigint NOT NULL,
status text NOT NULL DEFAULT 'pending',
total_cents integer NOT NULL,
is_paid boolean NOT NULL DEFAULT false,
metadata jsonb,
placed_at timestamptz NOT NULL,
PRIMARY KEY (id),
CONSTRAINT fk_customer
FOREIGN KEY (customer_id) REFERENCES customers (id)
);
CREATE INDEX idx_orders_customer ON orders (customer_id);
CREATE INDEX idx_orders_placed ON orders (placed_at DESC);Data movement & CDC
Parallel, checksummed, resumable bulk copy with per-table checkpoints. For zero-downtime moves, change-data-capture dual-write streams ongoing changes until target lag is near zero — then cutover is a routed switch.
#!/usr/bin/env bash
set -euo pipefail
# Parallel bulk copy — 8 workers, resumable checkpoints
morph copy \
--source "$SRC_DSN" \
--target "$DST_DSN" \
--tables orders,customers,line_items \
--workers 8 \
--checkpoint ./.morph/ckpt \
--checksum crc32
# Stream ongoing changes until lag < 250ms, then signal ready
morph cdc start --slot morph_cutover --resume
morph cdc wait --max-lag 250ms && echo "READY_FOR_CUTOVER"Validation & reconciliation
A suite you run against both databases and diff: row-count parity, aggregate checksums to catch silent value drift, and referential-integrity probes that must return zero rows before you cut over.
-- Run on BOTH databases; every result must match.
-- 1. Row-count parity
SELECT 'orders' AS table, count(*) AS rows FROM orders;
-- 2. Aggregate checksum (catches silent value drift)
SELECT
count(*) AS n,
sum(total_cents) AS sum_cents,
md5(string_agg(id::text, ',' ORDER BY id)) AS id_digest
FROM orders;
-- 3. Referential integrity — MUST return 0 rows
SELECT o.id FROM orders o
LEFT JOIN customers c ON c.id = o.customer_id
WHERE c.id IS NULL;Rollback plan
Explicit trigger conditions and a fast path back to the source. On the CDC path the source stays live and in sync, so rollback is a routed traffic switch with an RTO under a minute.
# Rollback plan — orders cutover
## Triggers (any one → roll back)
- Validation probe returns > 0 orphan rows
- p99 write latency > 400ms for 5 min
- Error rate on /checkout > 0.5%
## Procedure (RTO target: < 60s)
1. Flip the traffic router back to SOURCE.
2. Stop CDC dual-write: morph cdc stop --slot morph_cutover
3. Confirm source health-check is green.
4. Page the on-call DBA; freeze the target for triage.
> The source is never dropped until T+48h post-cutover.Operator runbook
A complete operator playbook: pre-flight checks, the ordered execution steps with time estimates, the cutover sequence, and post-cutover monitoring — so anyone on the team can run it with confidence.
# Operator runbook — MySQL → PostgreSQL
## Pre-flight (~20 min)
- [ ] Target provisioned, schema applied (01_schema.sql)
- [ ] Network path source ↔ target verified
- [ ] Maintenance window announced
## Execute (~3.5 h for 180 GB)
1. Start bulk copy → 02_move_data.sh (~3 h)
2. Start CDC dual-write → wait for READY (~25 m)
3. Run validation suite → 03_validate.sql diff (~10 m)
## Cutover (~2 min)
4. Freeze writes → flip router → unfreeze on target
## Post-cutover
- [ ] Watch dashboards 60 min · keep source warm 48 hSee it run on your migration.
Describe your source and target. In minutes you’ll have a fixed quote — and once you pay, every artifact you need to execute with confidence.