Capabilities

Every hard part of a migration, generated and verifiable.

Translation, movement, verification, recovery and operations — Morph turns each into a concrete file you can read, diff and run in your own environment. Here is exactly what the AI produces, step by step.

live · MySQL → PostgreSQLgenerating
SQL
PG
  • type-map synthesized48 cols
  • data scriptsparallel
  • validation suite9 probes
  • rollbackarmed
The migration engine

Analyze, quote, generate — one continuous pass

The same model that scores complexity writes the artifacts. Nothing is handed off, so the plan and the code never drift apart.

01
Analyze

Reads the shape of the move

Morph ingests the schema and metadata you provide — engines, versions, table count, volume, constraints — and builds a per-column type map, a dependency graph and a risk register. No connection, no data sampled.

02
Quote

Prices it deterministically

Complexity is scored, then a fixed one-time price is computed server-side from data volume, breadth, whether it crosses engines or paradigms, and your downtime tolerance. You see the number before you pay.

03
Generate

Writes every artifact

Target DDL, parallel data-movement scripts, a validation & reconciliation suite, a rollback plan with explicit triggers, and an operator runbook — concrete, reviewable files, not a recommendation deck.

Schema & type translation

Not a guess — a verified type map

Engine idioms rarely map one-to-one. Morph translates each column into the target’s native types and rewrites the structures that have no equivalent.

AUTO_INCREMENTGENERATED ALWAYS AS IDENTITY
ENUM(...) inlineCREATE TYPE … AS ENUM
TINYINT(1)BOOLEAN
DATETIMETIMESTAMPTZ + now()
JSONJSONB
source · orders.sql
mysql
CREATE TABLE orders (
  id            BIGINT AUTO_INCREMENT PRIMARY KEY,
  customer_id   BIGINT NOT NULL,
  status        ENUM('open','paid','shipped','void')
                  NOT NULL DEFAULT 'open',
  total_cents   INT UNSIGNED NOT NULL,
  metadata      JSON,
  is_gift       TINYINT(1) NOT NULL DEFAULT 0,
  placed_at     DATETIME NOT NULL
                  DEFAULT CURRENT_TIMESTAMP,
  KEY idx_cust  (customer_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
translated to
target · orders.sql
postgresql
CREATE TYPE order_status AS ENUM
  ('open','paid','shipped','void');

CREATE TABLE orders (
  id            BIGINT GENERATED ALWAYS AS IDENTITY
                  PRIMARY KEY,
  customer_id   BIGINT NOT NULL
                  REFERENCES customers (id),
  status        order_status NOT NULL DEFAULT 'open',
  total_cents   BIGINT NOT NULL CHECK (total_cents >= 0),
  metadata      JSONB,
  is_gift       BOOLEAN NOT NULL DEFAULT false,
  placed_at     TIMESTAMPTZ NOT NULL DEFAULT now()
);

CREATE INDEX idx_orders_cust ON orders (customer_id);
Data movement

Bulk, checksummed, then kept in lockstep

Change-data-capture for zero-downtime cutovers

Set downtime tolerance to none and the plan adds CDC dual-write: every change on the source replays to the target while the bulk load completes. Cutover becomes a routed traffic switch, with rollback armed the entire time.

dual-writereplay loglag monitorrouted switch
<0s
rollback RTO on the CDC path

Parallel bulk copy

Tables are partitioned and copied across workers, sized to your volume so a 600M-row table doesn't serialize behind a small one.

Checksummed & resumable

Each batch carries a checksum; an interrupted load resumes from the last verified offset instead of starting over.

Transform in flight

Column splits, unit conversions and encoding fixes are applied during movement — no second pass over terabytes.

validation · reconcile_orders.sql
sql
-- Reconciliation: must return 0 rows before cutover
SELECT 'orders' AS table_name,
       src.n  AS source_rows,
       tgt.n  AS target_rows,
       src.chk AS source_checksum,
       tgt.chk AS target_checksum
FROM   (SELECT count(*) n, md5(string_agg(
          id || '|' || total_cents, ',' ORDER BY id)) chk
        FROM source.orders) src
CROSS JOIN
       (SELECT count(*) n, md5(string_agg(
          id || '|' || total_cents, ',' ORDER BY id)) chk
        FROM public.orders) tgt
WHERE  src.n <> tgt.n OR src.chk <> tgt.chk;
Validation & reconciliation

Zero rows, or you don’t cut over

Morph generates a suite you run against both databases and diff. Every probe is designed to return nothing — any output is a discrepancy to resolve before cutover.

Row-count parity
per table, source vs target
Aggregate checksums
md5 over ordered key + value columns
Referential integrity
orphaned FK probes return zero
Spot-diff sampling
deterministic row samples compared field by field
Rollback & runbook

A way back, and a way through

Rollback plan

Explicit trigger conditions — not vibes. The plan names the exact metrics that abort a cutover and the precise sequence to restore the source as system of record.

  • Named abort triggers (lag, error rate, checksum drift)
  • Source kept live & in-sync on the CDC path
  • Step-reversible: every action has its inverse
  • Rehearsable in staging before the real window

Operator runbook

A timestamped playbook any engineer on the team can execute. Four phases, each with checks that gate the next.

  1. 1Pre-flightbackups verified, target reachable, CDC primed
  2. 2Executebulk load → catch-up → parity checks
  3. 3Cutoverfreeze, final reconcile, route traffic
  4. 4Post-cutoversmoke tests, monitor window, decommission
Per-migration AI assistant

An expert that already read your migration

Every project ships with a chat that has full context on your schema, type map, scripts and runbook. Ask why a column became JSONB, request a tweak to a batch size, or pressure-test the cutover — without re-explaining anything.

Why JSONB and not JSON?Make the rollback window 30 minExplain the FK on customer_idAdd an index for the reports query
morph · migration #1284 assistant context-aware
Why did total_cents become BIGINT?
MySQL’s INT UNSIGNED tops out at ~4.29B. PostgreSQL has no unsigned ints, so to preserve the full range without risking overflow I mapped it to BIGINT and added CHECK (total_cents >= 0) to keep the non-negative guarantee.
Ask about this migration…
0
artifacts per migration
0
engines, any direction
0.0%
fewer manual review hours
0h
hours for a 40-table cutover

A 40-table Postgres → MongoDB cutover, planned and scripted in 31 hours instead of three weeks.

Pay once. Migrate with confidence.

See it run on your own move

Describe your source and target. Morph scores complexity, quotes a fixed price, and generates every artifact — DDL, data, validation, rollback and runbook.