This is the deep version: you have decided to leave Oracle and land on Amazon Aurora PostgreSQL, and now you need to actually convert it. We walk the whole heterogeneous path — what AWS SCT auto-converts and which PL/SQL fights back (packages, sequences, autonomous transactions, CONNECT BY), how DMS full-load plus change-data-capture keeps Aurora live until cutover, the application data-access-layer changes nobody scopes upfront, how you validate that the data and behavior actually match, and a cutover with a real rollback. AWS MAP and database-migration funding can cover most or all of it, partner-led.
A homogeneous Oracle→Oracle move (to Amazon RDS for Oracle) copies bytes — same engine, same SQL, same PL/SQL, no rewrite. Oracle→Aurora PostgreSQL is the other kind of migration: the engine changes, so the schema, the procedural code, and the application’s assumptions about the database all have to be translated. That distinction governs everything below.
If you are still weighing lift-and-shift to RDS for Oracle against this re-platform, start with the broader decision page — Oracle to AWS lays out both paths and when each wins. This page assumes the decision is made: the database carries real Oracle licensing cost, it is tractable enough to convert, and your team will own PostgreSQL going forward. From here, the goal is to do the conversion well.
The target is Amazon Aurora PostgreSQL — a PostgreSQL-compatible engine with cloud-native storage that auto-scales to 128 TiB, replicates six ways across three Availability Zones, supports up to fifteen low-latency read replicas, and (the entire point) carries no database license. You pay for compute, storage, and I/O. Aurora is wire-compatible with community PostgreSQL, so the conversion target is "idiomatic PostgreSQL," and everything PostgreSQL-native — drivers, extensions, the planner — applies.
The honest mental model: roughly 80% of the calendar on a serious Oracle→Aurora project is not moving data. It is converting and rewriting the procedural code, changing the parts of the application that spoke Oracle, validating that behavior matches, and tuning a different query planner. DMS makes the data movement almost boring. The engineering lives in the schema and the application. The next sections follow that reality in order.
The Schema Conversion Tool does two jobs. It converts the schema and code it can, and — far more valuable on day one — it produces an Assessment Report that tells you object-by-object what it cannot, rated by difficulty. That report is the only honest way to size the project before you commit budget.
You point SCT at the source Oracle database and the target Aurora PostgreSQL endpoint and let it analyze the whole schema: tables, indexes, constraints, views, sequences, and the procedural code (packages, procedures, functions, triggers). It converts what it can and flags the rest, classifying each remaining action item as simple, medium, or complex. The headline number — percent of objects auto-converted — typically lands between 70% and 95%, and where you fall in that band is almost entirely a function of how much PL/SQL you carry and how Oracle-specific it is.
The structural layer converts cleanly almost every time. Datatype mapping is mostly mechanical: Oracle NUMBER lands on PostgreSQL numeric / bigint / integer depending on precision and scale, VARCHAR2 becomes varchar, DATE becomes timestamp (Oracle DATE carries a time component — a classic silent trap if you assume it is date-only), CLOB becomes text, BLOB becomes bytea, and RAW/ROWID need explicit decisions. SCT does the mapping and flags the NUMBER columns whose precision a human should confirm. Tables, indexes, views, and check constraints come across with little drama. The hours go somewhere specific and predictable, and naming them up front is what keeps a project from stalling mid-stream.
For the genuinely hard objects, SCT can deploy an extension pack and, for some constructs, emulate Oracle behavior on the PostgreSQL side rather than rewriting it by hand. Treat that as a pragmatic accelerator and as technical debt — useful for the long tail, not a license to skip idiomatic rewrites of code that runs hot. The disciplined sequence is: take the auto-converted objects, manually rewrite the medium/complex action items into clean PL/pgSQL, and reserve emulation for the cases a proper rewrite cannot yet justify.
The most valuable artifact of this phase is not the converted schema — it is the number plus the action-item list. "This database is 88% auto-convertible with 240 complex items, concentrated in three ETL packages and the audit framework" is a project you can staff and schedule. A 95%-convertible reporting mart is a quick win; a 72%-convertible core-transaction schema with six-figure PL/SQL line counts is a real engineering program. SCT lets you make that call with evidence instead of optimism.
Oracle’s PL/SQL is a richer procedural language than PostgreSQL’s PL/pgSQL, so the gaps are concrete. These are the objects that consume the manual conversion budget on essentially every Oracle→Aurora migration:
Teams researching Oracle migration often hit Babelfish for Aurora PostgreSQL and hope it is a fast lane. It is not — for Oracle. Babelfish is a translation layer that lets Aurora PostgreSQL understand Microsoft SQL Server’s T-SQL and TDS wire protocol, so applications keep their SQL Server queries. There is no equivalent that makes Aurora speak Oracle’s PL/SQL or SQL*Net. For Oracle→Aurora the path is genuine conversion via SCT + DMS. (If part of your estate is SQL Server, Babelfish is very relevant there — see SQL Server to AWS.)
With the schema built on Aurora, the Database Migration Service moves the data and — the part that matters — keeps it moving. DMS change-data-capture is what turns a dreaded weekend cutover into a controlled switch measured in minutes.
A DMS task runs in up to three modes. Full load bulk-copies existing rows from Oracle into Aurora. CDC then reads Oracle’s redo logs and continuously applies every subsequent insert, update, and delete to Aurora. Run "full load plus CDC" and DMS first copies the data, then settles into a steady state where Aurora trails live Oracle by seconds. The source stays fully online throughout — users never know a migration is underway. You can let that replication run for days or weeks while you validate, test the application against Aurora in staging, and tune performance.
Operationally there are real knobs, and a seasoned migration team turns them deliberately. The replication instance is sized to the change rate; high-volume systems are parallelized across multiple tasks split by table or schema. Large-object (LOB) columns need explicit handling — full LOB mode is complete but slow, limited LOB mode is fast but truncates beyond a set size — so you choose per workload. For best throughput on the initial load you typically create secondary indexes, foreign keys, and triggers after the full load rather than before, then enable them for the CDC phase. And CDC requires Oracle supplemental logging enabled on the source so the redo stream carries enough column data to replay changes.
Be clear about DMS’s boundary: it replicates row changes, not logic. It does not migrate procedural code (that is SCT’s job and your rewrites), it does not convert schema, and it will not invent referential integrity you did not define. DMS moves and syncs the data; SCT and your engineers move the behavior. Keeping that line crisp is what prevents the "we thought DMS handled the triggers" surprise late in a project.
DMS includes built-in data validation that compares source and target row-by-row after the full load and during CDC, reporting mismatches rather than asking you to trust the pipe. For anything mission-critical this is non-negotiable: you validate row counts, run checksums on the critical tables, and add application-level reconciliation queries that re-compute key business aggregates on both sides. The pairing — DMS validation for fidelity plus your own business reconciliation for meaning — is what lets a CFO, an auditor, or a regulator accept that the Aurora copy is now the system of record.
SCT converts the database and DMS moves the data, but neither touches your application. A surprising amount of Oracle-specific behavior lives in the app tier — the SQL your code emits, the driver it loads, and the assumptions it makes — and scoping this honestly is the difference between a 4-month project and a 9-month one.
Start with the connectivity layer. Oracle clients use the oracle JDBC driver / OCI / SQL*Net and an Oracle connection string and SID/service name; Aurora PostgreSQL uses the PostgreSQL JDBC (or libpq, psycopg, node-postgres, etc.) driver and a standard PostgreSQL DSN. ORMs and query builders need their dialect switched (Hibernate dialect, Django/Rails/Sequelize adapter, SQLAlchemy URL). This is mechanical but touches configuration, secrets, and every service that holds a connection — and connection-pool behavior differs enough that you tune pool sizes for PostgreSQL rather than assume the Oracle settings carry over.
Then the SQL the application emits directly — the inline queries, the report builders, the stored-SQL fragments that never went through SCT because they live in application code, not the database. These carry the same dialect gaps SCT flagged in the schema: ROWNUM and Oracle pagination become LIMIT/OFFSET or keyset pagination; (+) outer joins become ANSI joins; NVL/DECODE/SYSDATE need translating; sequence access changes; and — the subtle one that bites in production — Oracle treats '' (empty string) as NULL while PostgreSQL treats it as a zero-length string, so WHERE col = '' and IS NULL checks behave differently. Case-sensitivity of unquoted identifiers and date/number formatting via NLS settings differ too.
Finally, behaviors your code may quietly depend on: default transaction isolation and locking semantics differ between Oracle and PostgreSQL; sequence-generated IDs may not be perfectly gap-free; and anything that read CURRVAL, used Oracle hints, or relied on implicit type coercion needs review. None of this is exotic, but it is invisible until you go looking, which is exactly why a partner who has migrated applications off Oracle inventories the data-access layer during assessment rather than discovering it during cutover.
Correct data is necessary but not sufficient. The application has to behave identically and perform acceptably on an engine whose optimizer makes different choices than Oracle’s. This phase is where re-platforms are actually de-risked.
Run validation on three levels. Data fidelity comes from DMS validation plus your reconciliation queries (covered above). Functional correctness comes from your application regression suite executed against Aurora — ideally the full suite, with particular attention to the converted PL/pgSQL objects and any code path that touched the rewritten SQL. Behavioral equivalence comes from comparison testing: run representative read and write workloads against both Oracle and Aurora and diff the results, which surfaces the empty-string-is-NULL and date-truncation class of bugs that pass unit tests but change query results.
Performance is its own workstream because PostgreSQL’s planner is not Oracle’s. Queries that were fast on Oracle can choose a different plan on Aurora; you tune by running production-representative load against Aurora before cutover, reading EXPLAIN ANALYZE, adding or reshaping indexes (PostgreSQL partial and expression indexes are powerful here), and making sure autovacuum and statistics (ANALYZE) are configured so the planner has good estimates. Connection pooling — PgBouncer or RDS Proxy — usually matters more on PostgreSQL than teams expect for high-concurrency apps. Budget an explicit tuning phase; "it was instant on Oracle" is not a guarantee on day one, and discovering that in production is the avoidable failure mode.
The discipline that makes all of this tractable is sequencing: migrate a non-critical database first to prove the toolchain and the team’s PostgreSQL muscle, then graduate to the systems the business runs on. The first migration teaches you your own application’s Oracle-isms cheaply; the critical one then benefits from a rehearsed process rather than a first attempt.
The conversion and the data move are engineering. The cutover is risk management. For a system the business depends on, the entire migration is judged on one question: what happens if something is wrong at the moment of switch?
The answer is a rehearsed runbook with a rollback you do not have to invent under pressure. The single most important design choice is to keep the source Oracle database authoritative until the cutover is proven. Because DMS CDC syncs Aurora from Oracle (not the reverse), rollback during the window is trivial: if validation fails after you switch, you repoint the application back to Oracle, which never stopped being correct. You only burn that bridge once you are certain. A typical mission-critical cutover runs like this:
None of this removes risk entirely — a heterogeneous migration of a core system is genuinely hard — but migrating non-critical databases first, rehearsing the cutover, and keeping the rollback explicit converts an unbounded risk into a bounded, reversible event. That discipline is precisely what you are paying a vetted migration partner for, and precisely what AWS MAP funds them to execute well.
The conversion costs real engineering, so the model has to clear it. For Oracle→Aurora it almost always does, because the recurring Oracle bill it deletes is large and perpetual while the conversion is one-time.
Build it on three lines. First, the Oracle cost you delete: licenses (per processor, after the core-factor multiplier), the ~22% annual support renewal, the options the schema depends on (Partitioning, Advanced Compression, Diagnostics and Tuning Packs, Active Data Guard, RAC) — each licensed separately and per-core — plus the hardware refresh and DR standby if you run it yourself. A single Oracle Enterprise Edition processor license lists around $47,500, and one physical core often counts as more than one "processor" once the core-factor table is applied, so a mid-sized estate carries a seven-figure annual Oracle bill before anything new ships. Second, the Aurora cost you take on: compute (instance hours or Aurora Serverless v2 capacity), storage, I/O, and backups — with no license layer at all. Third, the one-time conversion: SCT/DMS work, PL/SQL and application rewrites, testing, and cutover — the line MAP and database-migration funding are designed to offset.
In practice, moving a workload off Oracle Enterprise Edition with options to Aurora PostgreSQL cuts database TCO by roughly 60–90%. It skews higher when you were paying for expensive options and a DR standby — Aurora provides Multi-AZ HA, automated backups, and read replicas natively, with no per-feature licensing — and lower when you were already on Standard Edition. Payback on the conversion is commonly under a year on the support renewal alone, which is why these projects survive CFO scrutiny that kills most "modernization" initiatives. The one caveat that keeps the model honest: the savings are real only after decommission. While Oracle runs in parallel as a safety net you are paying for both, so the decommission date is a line item, not an afterthought.
A funded, done-for-you Oracle→Aurora migration is the CloudRoute mechanism. You do not assemble an internal SCT/DMS team from scratch and learn PostgreSQL’s edge cases live on a production database — you get matched to a vetted AWS partner who has done heterogeneous Oracle migrations before, and AWS funding covers most or all of the engagement.
The vehicle is the AWS Migration Acceleration Program (MAP), run through the AWS Partner Network in three phases. Assess is a TCO and readiness analysis — the partner runs SCT across your Oracle databases to produce the auto-convertibility numbers, the action-item inventory, and a real savings model; this phase is frequently AWS-funded and gives you go/no-go data before you commit a dollar. Mobilize builds the AWS landing zone and pilots the conversion of a representative database. Migrate & Modernize is the production conversion, the CDC cutover, and stabilization. AWS provides credits and funding scaled to the migration’s size across these phases, and there are AWS programs aimed specifically at database migrations off commercial engines like Oracle.
The honest framing matters: MAP funding applies to qualifying migrations — typically those with a meaningful committed AWS spend after migration — and the exact amount is scoped during Assess. For a substantial Oracle estate that clears the bar, the conversion can be largely or entirely AWS-funded. For smaller workloads that do not qualify for full funding, the value is still real: a partner who has converted Oracle PL/SQL and run DMS CDC cutovers de-risks the hardest parts, rather than your team meeting SCT’s extension pack and PostgreSQL’s planner for the first time on a system the business runs on.
CloudRoute’s role is the routing. You tell us the shape of the estate — how much Oracle, which editions and options, how much PL/SQL, what the databases do, your timeline — and we match you to a partner with a genuine Oracle→Aurora track record and the AWS tier to file MAP. The partner runs the assessment, scopes the funding, and executes. AWS funds the engagement; the partner is paid through MAP; CloudRoute is paid a commission by the partner. You see no invoice from us.
For the data-movement engine in depth, see AWS Database Migration Service. The funding mechanics tie into the AWS credits cluster — $100K AWS credits and how AWS POC funding works. The platform you land on should be a secure, multi-account AWS landing zone. And the migration offer page lays out exactly what a CloudRoute-routed, MAP-funded migration includes.
This is the table the conversion turns on: for each Oracle construct, what it becomes on Aurora PostgreSQL and how hard SCT plus your engineers have to work to get it there. "Easy" is largely automatic; "hard" is where the manual PL/SQL budget goes.
| Oracle feature | Aurora PostgreSQL equivalent | Conversion difficulty |
|---|---|---|
| Tables, indexes, views, check constraints | Direct equivalents | Easy — SCT auto-converts |
| Datatypes (NUMBER, VARCHAR2, DATE, CLOB, BLOB) | numeric/int, varchar, timestamp, text, bytea | Easy–Medium — DATE carries time; NUMBER precision needs review |
| Sequences (NEXTVAL / CURRVAL) | Sequences + GENERATED AS IDENTITY / serial defaults | Medium — idiom + insert-trigger pattern changes |
| Hierarchical queries (CONNECT BY / START WITH) | WITH RECURSIVE common table expressions | Medium — deep/cyclic cases hand-written |
| Built-ins (DECODE, NVL, ROWNUM, SYSDATE) | CASE, COALESCE, LIMIT/row_number(), now()/clock_timestamp() | Medium — many auto, semantics differ subtly |
| Triggers & materialized views | PostgreSQL triggers; full/concurrent matview refresh | Medium — firing semantics + no fast-refresh analog |
| Partitioning | Declarative partitioning | Medium — strategy maps, not always 1:1 |
| Packages | Schema of functions/procedures | Hard — no native package; state & overloading manual |
| Autonomous transactions (PRAGMA) | dblink loopback or pattern redesign | Hard — no direct equivalent |
| BULK COLLECT / FORALL / collections | Set-based SQL or array operations | Hard — common rewrite in heavy ETL |
| Empty-string = NULL semantics | Empty string ≠ NULL (must reconcile in app + SQL) | Hard to find — silent behavioral bug if missed |
| RAC / Active Data Guard / Partitioning options | Native Aurora HA, replicas, backups (no license) | N/A — replaced, not converted (this is the savings) |
Situation: Oracle support renewal nine months out and a board mandate to cut infrastructure cost. The core order/billing database held ~95K lines of PL/SQL — including an audit framework built on autonomous transactions, three heavy nightly ETL packages using BULK COLLECT, and a category tree driven by CONNECT BY. The application was a Java/Hibernate monolith plus two Node services, all on the Oracle JDBC driver, with a few hundred inline queries using ROWNUM pagination and (+) joins. No one on staff had run a heterogeneous Oracle→PostgreSQL migration.
What CloudRoute did: Routed within 24 hours to an AWS Premier partner with a database-modernization specialization and a documented Oracle→Aurora track record. MAP Assess (AWS-funded) ran SCT: the two reporting databases came back 94–96% auto-convertible; the core OLTP database 81%, with the heavy items concentrated exactly where expected — the autonomous-transaction audit framework, the three ETL packages, and the CONNECT BY hierarchy. The partner converted the reporting databases first as the toolchain pilot, then rewrote the core PL/SQL into idiomatic PL/pgSQL (audit moved to a queue-and-write-outside-txn pattern; ETL re-expressed as set-based SQL; hierarchy as WITH RECURSIVE), swapped the application to the PostgreSQL JDBC driver and pg adapters, and remediated the inline SQL. DMS full-load + CDC ran 6 weeks in sync under full regression and production-load testing; the core database cut over in a 26-minute window with a rehearsed rollback to Oracle that was never needed.
Outcome: All three databases live on Aurora PostgreSQL over ~6.5 months. Oracle decommissioned on schedule — annual database TCO down ~78% (from ~$620K to ~$135K on Aurora, including Serverless v2 for the reporting workloads). A two-week post-cutover performance-tuning pass (new indexes, PgBouncer pooling, autovacuum tuning) closed the gap on three slow report queries. The engagement was MAP-funded against the post-migration AWS commitment; CloudRoute’s commission was paid by the partner. The customer paid $0 for the migration itself.
core DB: 3.1 TB / ~95K LOC PL/SQL · timeline: ~6.5 months · database TCO cut: ~78% · cutover downtime: 26 min · migration cost to customer: $0 (MAP-funded)
CloudRoute routes you to a vetted AWS partner who runs the SCT assessment, rewrites the hard PL/SQL, executes the DMS CDC cutover with a tested rollback, and scopes MAP funding. AWS funds qualifying migrations. No DIY conversion learning curve on your production database.