Skip to main content
Clinton Agada
Case study · 2021 — 2022

Mongo → Postgres while the lights stayed on.

A zero-downtime migration from MongoDB to PostgreSQL for a healthcare platform with continuous real-world traffic. Two-way sync, custom indexes, redesigned API. Twelve months from kickoff to shutdown.

RoleBackend lead
Team3 engineers
StagePlan → cutover → sunset
IndustryHealthcare · production
0sDowntime · cutover
−30%+Infra cost · ongoing
−42%Query p95 latency
12moPlan → sunset

The architecture, during the two-database phase

The five phases, by traffic split

01

Read-write Mongo only

Months 0 — 1 · pre-migration baseline

Capture latency, throughput, and query-shape baselines. Write the migration playbook before writing any migration code.

Traffic split · reads / writes
100% Mongo
100% Mongo
02

Postgres shadow

Months 2 — 4 · dual-write

Every write hits both databases. Reads still come from Mongo. Sync service polices any drift.

Traffic split · reads / writes
100% Mongo
50% Mongo
50% Postgres
03

Postgres read trickle

Months 5 — 7 · staged read cutover

5% to 75% of reads served from Postgres, by endpoint risk class. Rollback stays a feature flag away.

Traffic split · reads / writes
25%
75% Postgres
50% Mongo
50% Postgres
04

Postgres primary

Months 8 — 10 · write cutover

Writes flip to Postgres-first. Mongo becomes the warm shadow. Nobody fell back.

Traffic split · reads / writes
100% Postgres
100% Postgres
05

Mongo shutdown

Months 11 — 12 · sunset

Cluster decommissioned. Sync service archived. Infra cost drops from baseline. Playbook closed.

Traffic split · reads / writes
100% Postgres
100% Postgres

The problem

A healthcare platform on Mongo since 2017 had outgrown the model.

The data was relational in spirit and document in storage; every new feature required a compensating index; the bill was climbing.

The approach

The plan was the deliverable. Before any sync service, before any schema, I wrote a playbook covering the five traffic phases, rollback paths, success criteria, and alarms.

The technical heart was a small sync service reading Mongo's change stream and writing into Postgres, plus a reverse path doing the same thing the other way.

Migrations are 20% data, 80% organisation. The schema was the easy half.From the post-migration retro

The hard bits

  • Schema embedding vs joins. Mongo embedded patient to encounters to observations. Postgres normalized them. The API kept the embedded read path alive with a read-side view.
  • Indexes for compatibility, then cost. Phase-one indexes mirrored Mongo query shapes; phase-two indexes were rewritten for the Postgres planner.
  • The reverse sync. Postgres to Mongo required a versioning scheme that did not exist in the original schema.
  • Rollback belief. The rollback plan had to be real enough that the team trusted every phase.

What I'd do differently

I would write the reconciliation job in week one. We wrote it in month four after spending three months arguing about whether we needed it.

I would buy managed Postgres earlier. The infra savings came partly from leaving Mongo, but also from picking a better Postgres host.

Next01

Read another case study

2025Now

Edulinks.ng — a community on the company stack

Veraclins's Q&A and learning community for Nigerian students, built on the company's shared design system and tooling.

Read →