Skip to content

MongoDB CDC to PostgreSQL Final State Guide

June 2026

MongoDB to Postgres works best when change-stream documents and PostgreSQL upserts are treated as one final-state contract.

Short Answer

MongoDB CDC to PostgreSQL works by reading MongoDB change streams, which emit insert, update, and delete operations backed by the oplog, then reconciling those mutations into PostgreSQL with a staging table plus INSERT ... ON CONFLICT logic. Skippr adds a _skippr_order_token column and a companion tombstone table so older replays do not overwrite newer state or resurrect deleted keys.

A concrete example is a users document with _id 42. If MongoDB emits an update and fullDocument: updateLookup returns the after image with a new email, Skippr only updates the PostgreSQL row when the incoming order token sorts after the current one. If MongoDB later emits a delete for _id 42, Skippr records the tombstone and removes the target row.

Why Teams Struggle with This

This integration gets tricky at the seam between document CDC and relational reconciliation. MongoDB restart safety depends on resume tokens, while PostgreSQL correctness depends on a stable row key and a merge path that compares order tokens every time the same document shows up again.

  • MongoDB CDC requires a replica set or sharded cluster because change streams depend on the oplog.
  • Updates arrive as change-stream events and rely on fullDocument after images, so the destination must reconcile versions rather than append every mutation forever.
  • PostgreSQL uses staging plus INSERT ... ON CONFLICT with a newer-token-only guard, so a weak row key will show up as wrong final state quickly.
  • Deletes need tombstone tracking, otherwise an older replayed insert can bring back a row that should stay deleted.

How Skippr Handles It

Skippr keeps the two sides of this integration aligned. On the source side it stores the MongoDB resume token after each committed batch and resumes the stream with resume_after. On the destination side it creates the PostgreSQL _skippr_order_token column and companion tombstone table automatically, then uses the documented staging-then-merge pattern.

That makes the integration easier to explain in production. You can point to what MongoDB emitted, which token won, and why the PostgreSQL table now shows the current document state instead of an append-only event history.

  • MongoDB source support for insert, update, and delete events through change streams.
  • Resume-token restart behavior so the stream continues from the last committed batch.
  • PostgreSQL staging plus INSERT ... ON CONFLICT reconciliation with newer-token-only updates.
  • Automatic tombstone tables to block ghost resurrections after deletes.

What the First Useful Version Looks Like

This integration is a good fit when MongoDB is the system of record but analysts or downstream apps want current-state tables in PostgreSQL.

The design question to settle early is simple: which document key should PostgreSQL treat as row identity, and do you want every replay to lose unless its order token is newer?