Oracle to PostgreSQL Migration: 2 Methods and Checklist
If you're running Oracle in production, you've probably felt the pain. The licensing bills keep climbing. Your infrastructure is tied to one vendor. And every time you want to try something new, there's another Oracle-specific constraint standing in your way.
PostgreSQL offers a way out. It's open-source, and runs beautifully on every major cloud platform. More and more engineering teams are making the switch.
This guide walks you through everything you need to know to migrate from Oracle to PostgreSQL confidently. We'll cover the key differences between the two databases, the two main migration approaches, and a step-by-step guide for each.
Oracle vs. PostgreSQL: Key Differences to Know First
Understanding the structural differences between Oracle and PostgreSQL is the first step in a smooth migration. A lot of migrations run into trouble not because of bad planning, but because teams underestimate how different they actually are under the hood. Here's the differences that matte most.
Architecture
Oracle uses a multitenant model built around a container database (CDB) that hosts one or more pluggable databases (PDBs). PostgreSQL uses a simpler schema-based model. This means you'll likely need to rethink how your databases and schemas are structured before you migrate.
SQL dialect
Oracle has its own SQL extensions that PostgreSQL simply doesn't support. These are scattered throughout application code and stored procedures, and they'll break silently if you don't catch them. Here are the most common ones:
| Oracle | PostgreSQL equivalent |
|---|---|
ROWNUM | LIMIT |
SYSDATE | NOW() |
CONNECT BY | WITH RECURSIVE |
SELECT 1 FROM DUAL | SELECT 1 |
NVL(x, y) | COALESCE(x, y) |
Procedural language
Oracle’s procedural language is PL/SQL, which is very robust and feature-rich. PostgreSQL uses PL/pgSQL. While they look similar, there are nuances in how exceptions are handled and how cursors behave. Most PL/SQL logic can be mapped to PL/pgSQL, but complex packages might require manual rewriting.
Data types
Oracle's type system doesn't map cleanly to PostgreSQL. This is where silent data loss can happen if you're not careful. Here is a quick reference for common mappings:
| Oracle | PostgreSQL |
|---|---|
NUMBER(p,s) | NUMERIC(p,s) |
VARCHAR2(n) | VARCHAR(n) or TEXT |
DATE | TIMESTAMP (Oracle DATE includes time — PostgreSQL DATE does not) |
CLOB | TEXT |
BLOB | BYTEA |
RAW | BYTEA |
