Home/Blog/DynamoDB to PostgreSQL Migration: A Practical Guide
Data migration

DynamoDB to PostgreSQL migration: keys, types and cutover

Plan a DynamoDB to PostgreSQL migration with typed exports, source key mapping, JSONB checks, change reconciliation and a controlled application cutover.

Remqa · November 10, 2026 · 5 min read

Short answer

To migrate DynamoDB to PostgreSQL, define the target entities and access patterns, preserve source keys and types, then load a traceable export into staging before transforming it. Reconcile changes and deletions against a recorded extraction boundary, test application behavior and choose one authoritative writer at cutover. A completed scan or export alone does not prove the target is ready.

  • Keep DynamoDB type information until target conversion has been validated
  • A strongly consistent Scan still does not provide snapshot isolation
  • Use export manifests to track complete input coverage
  • Test changed and deleted items before switching application writes

Your application can read the migrated rows, but a customer history screen is empty. The loader copied the documents and missed the relationships encoded in their keys. A DynamoDB to PostgreSQL migration needs to preserve the application's behavior as well as its stored values. Moving JSON into a column is only one part of that work.

Begin with the queries and writes the application actually performs. Then design the target tables, extraction boundary and reconciliation checks. The workflow below is an engineering recommendation. It does not imply that DynamoDB exports automatically create a working PostgreSQL database or that a particular downtime window is guaranteed.

Map application access patterns before mapping fields

Inventory the requests that create, update and retrieve each business entity. Record the keys used, expected result order, tenant scope and behavior when a record is missing. Include background workers, reports and administrative tools. A successful web request is not enough if a scheduled writer still depends on the source representation.

For each source item shape, decide whether it becomes a relational row, a child collection or a retained document. Preserve the original source key alongside any new target identifier. If the source uses a composite key, keep both components without ambiguous concatenation. Explain how each source item maps to the target so a failed business check can be traced back.

Do not force every item shape into the same table just because the source stored them together. Equally, do not split every nested field without a query requirement. Treat this as part of the application change described in our code migration approach, not a loader-only project.

Choose and record the extraction boundary

DynamoDB export to S3 requires point-in-time recovery to be enabled. It supports full and incremental exports in DynamoDB JSON or Amazon Ion. Record the source table, requested export time or interval, export identifier and output format. Verify permissions and successful export completion before accepting files as input.

A full export gives the table representation for the requested point within the recovery window. Do not assume this guarantees transactionally consistent business records. AWS explicitly warns that exported data is not transactionally consistent and transaction changes can be split across export outputs. Validate related business records and reconcile the boundary before cutover.

If you use Scan instead, paginate to completion. A Scan reads up to its configured item limit or the documented data boundary before applying its filter. A page can contain no matching items while still returning LastEvaluatedKey. Continue using that key as ExclusiveStartKey rather than treating an empty page as completion.

A strongly consistent scan is not a frozen table. ConsistentRead strengthens individual item reads but does not provide snapshot isolation across the Scan. Decide how you will reconcile concurrent changes, or use an agreed write pause with a verified final load.

Keep the export manifest and original types

DynamoDB exports contain summary and files manifests. Use the files manifest as the list of expected data files rather than loading whatever happens to be present under a shared storage prefix. Store the export identity, file identity and processing result in a private migration journal. Restart from that journal without silently skipping failures.

DynamoDB JSON uses type wrappers. A value tagged N is not the same representation as a plain JSON number, and a set is not simply an ordered list. Keep the original tagged record in restricted staging until conversion and reconciliation have passed. Preserve failed rows with an explicit reason and a controlled way to reprocess them.

Source representationTarget decisionCheck before acceptance
Source key componentsPreserved identity columns or mapping recordNo collisions between entity shapes or tenants
Number wrapperReviewed numeric conversionNo intermediate floating point rounding
String or numeric setExplicit set representationMembership and duplicate handling match requirements
Map or listJSONB or related rowsNested values and meaningful list order survive
Missing or null attributeWritten presence ruleUnknown, absent and explicitly cleared stay distinguishable

Test JSONB conversion instead of assuming equivalence

PostgreSQL JSONB does not preserve object key order, whitespace or duplicate object keys. It also rejects numbers outside PostgreSQL numeric's range and has Unicode input restrictions. Preserve original input outside the converted representation if exact source text matters for audit or recovery.

Avoid passing precise numeric strings through an ordinary floating point parser before writing them. Test the transformation path end to end with actual source values. Decide explicitly how binary values will be represented and how source set types will remain distinguishable from ordered lists when that difference matters to the application.

JSON null and SQL NULL are different concepts. Add tests for a missing source attribute, an explicit null, an empty collection and an empty string. The target application must know whether to leave a value unchanged, clear it or reject it. A generic cleanup that makes all four identical can change business behavior.

Reconcile inserts, changes and deletions

For an active source, define how changes after the initial extraction reach the target. Incremental exports contain compacted item state for the selected interval, not every intermediate event. Do not use them as an assumed complete event history for billing, notifications or business audit.

Process deletions as well as new images. Keep the intervals and source keys in the migration journal so an older batch cannot silently replace a newer accepted state. Write and test your replay policy before running overlapping loads. If the design cannot account for changes reliably, agree a controlled pause rather than presenting a partial sync as current.

Compare coverage by entity type and tenant. Then compare relationships, values and application results. Raw counts alone are insufficient when one source item can produce several target rows. The broader data migration plan should state which differences are intentional and who accepts them.

Use a cutover checklist with a real recovery decision

  1. Complete the input inventory and resolve or explicitly accept every rejected transformation.
  2. Reconcile the final change boundary, including deleted records and related entities.
  3. Run application reads and writes against the target, including tenant checks and background tasks.
  4. Switch to one authoritative write path and verify that old workers cannot continue writing unnoticed.
  5. Record the recovery boundary and how target-only writes would be preserved if a return to the source is required.

Keep source access restricted during the agreed validation period. Retaining the source helps investigation, but it does not automatically make rollback safe. New target writes create another reconciliation problem. Test that recovery path before relying on it.

How Remqa approaches DynamoDB migrations

Remqa can help define the target model, build typed staging and conversion, and connect reconciliation to application cutover checks. Start with representative item shapes and the screens or jobs that use them. Include unusual records, not just the simplest successful export.

Bring a sample schema, access pattern list and current writer inventory to a call. An engineer can discuss a bounded migration plan and the checks needed before moving production traffic.

FAQ

Questions people ask.

Can DynamoDB data be exported for a PostgreSQL migration?

Yes. DynamoDB export to S3 supports DynamoDB JSON and Amazon Ion and requires point-in-time recovery to be enabled. The exported files need a separate transformation and loading process for PostgreSQL.

Does ConsistentRead make a DynamoDB Scan a snapshot?

No. Strong consistency applies to individual item reads. DynamoDB does not provide snapshot isolation for a Scan, so a changing table can yield reads from different points during the scan.

Can DynamoDB JSON be copied directly into JSONB?

It can be retained as a tagged staging representation, but that is not the same as a converted application document. Decode the DynamoDB type wrappers and define how numbers, sets, binary values and missing attributes should behave in the target.

Is an incremental export a complete event history?

No. AWS describes incremental exports as compacted output containing an item once with its final state for the period, even when it changed several times. Treat it as change reconciliation input rather than a complete sequence of business events.

Can this migration guarantee zero downtime?

No generic guide can make that promise. The cutover depends on application write paths, reconciliation, validation and recovery. Choose a tested change capture design or an agreed write pause rather than assuming an export keeps both systems synchronized.

Talk to an engineer

Want an engineer to look at your setup?

Book a free 30-minute call. We look at your tools and your team's week and tell you what we would do first.

Book a free 30-minute call
30 minutesFree, with an engineer
Your stackWe look at what you run today
Straight answerIncluding when we're not the fit