Every database migration has the same false summit. The full load finishes, row counts line up, the dashboard hits 100%, and someone wants to declare victory. Then you go looking for the foreign keys, the triggers, the stored procedures your reporting actually runs on, and none of them are there.
That is not a bug. It is AWS Database Migration Service working exactly as designed. DMS moves table data and primary keys. Almost everything else that turns a pile of tables into a working system, it leaves to you. Knowing where that line falls is the difference between a migration you scoped correctly and one that blindsides you two weeks before cutover.
What DMS actually carries across
The cleanest mental model: DMS is a very good removals company for your rows. It picks up the data, keeps the source running while it works, and puts the rows down in the new house. It does not rebuild the house.
When a DMS task creates a table on the target, it brings the column definitions, the data, and the primary key. That is the full extent of what you can assume. Everything below travels separately, or not at all.
The objects DMS leaves behind (and why each one bites)
"DMS does not migrate schema objects" is technically true and practically useless. What matters is the consequence of each gap on cutover day.
| Object DMS skips | What happens if you forget it |
|---|---|
| Secondary indexes | The data is all there, and every report runs at a crawl. Queries that were instant on the source do full scans on the target. |
| Foreign keys | Referential integrity silently disappears. Orphan rows creep in and nobody notices until a finance report double-counts. |
| Triggers | The side effects your app quietly depended on (audit rows, derived columns) stop firing. |
| Views | Anything reading from a view breaks the moment it points at the new database. |
| Stored procedures & functions | On a real EDW this is the whole application logic. None of it comes across. |
| Users, roles, privileges | Day one on the target, nobody can log in with the right permissions. |
So the honest answer to the most-searched version of this question, "does AWS DMS migrate stored procedures?" is no. Not stored procedures, not functions, not packages, not triggers. Those are code, and DMS moves data. Code needs a different tool.
The two-step reality: SCT converts, DMS moves
This is the part that reframes how you plan. A migration where the target engine differs from the source (Oracle to PostgreSQL, SQL Server to Aurora, Sybase to Redshift) is a heterogeneous migration, and it is genuinely two projects:
- Convert the schema and code with the AWS Schema Conversion Tool (SCT). It translates tables, and attempts your procedures, functions and views into the target dialect. The word attempts is load-bearing: SCT flags what it cannot convert automatically, and that action-item list is your real backlog.
- Move the data with DMS, once the target has somewhere to put it.
A homogeneous migration (same engine to same engine, like on-prem PostgreSQL to RDS PostgreSQL) is a single step and much lighter, because no dialect translation is needed. DMS even has a homogeneous mode that uses the database's own native tools and can bring secondary objects along.
The trap is assuming every migration is the easy kind. If your source and target engines differ, you own a schema-and-code conversion whether you planned for one or not.
Full load plus CDC: the zero-downtime part DMS is genuinely good at
Credit where it is due. The thing DMS does well is move data without freezing your source. A task runs in phases: a full load of the existing rows, then change data capture (CDC) that tails the source's transaction log and replays every insert, update and delete onto the target. You keep both in sync until you are ready to flip.
That is what "zero-downtime migration" actually means in practice. You are not copying a frozen snapshot. You are copying a moving one and keeping pace.
Two caveats worth internalising before you promise a business a zero-downtime cutover:
- CDC is not real-time. There is always replication lag, and it grows with source write volume, network conditions, and how hard the target can ingest. Plan the cutover around a lag you have actually measured, not zero.
- DMS can fail silently. If the replication instance runs out of storage or hits memory pressure, a task can stall or stop with no obvious error. Watch
FreeableMemoryand the instance storage, and set CloudWatch alarms before you trust it overnight.
I lean on this same log-tailing pattern outside of DMS too. On a fully-automated ETL pipeline moving millions of records a day, the win came from Apache Hudi upserts that rewrote only the rows that changed instead of rebuilding tables. Same principle: process the delta, not the whole world. It is why CDC-style migration feels natural once you have built pipelines that think incrementally.
The gap DMS cannot close for you: proof
DMS has a built-in data validation feature, and you should turn it on:
{
"ValidationSettings": {
"EnableValidation": true,
"ThreadCount": 5,
"FailureMaxCount": 10000
}
}This row-compares source and target after the load and flags mismatches: truncated columns, type coercions that quietly corrupted a value, rows that never arrived. That is real and useful. Enable it.
But be clear about what it proves and what it does not. Row-level validation tells you the data matches. It says nothing about whether the stored procedure you re-wrote returns the same number as the original, whether a foreign key you forgot to recreate is now letting bad rows in, or whether a report built on a converted view still balances. Those are correctness questions about the 20% DMS never touched, and only your own tests answer them.
This is the part I have spent the most real effort on. On a Sybase-to-Redshift migration I led for a tier-1 bank, moving the data was the least of it. The work was re-engineering 800+ stored procedures the reporting depended on, and building an automated test harness that checked every table against source until we reached 95% validation accuracy. Throughput ended up about 40% higher on Redshift, but that was the reward, not the job. Whether you move the rows with DMS, a bulk COPY from S3, or anything else, the rows are never the hard part. The 800 procedures are. DMS is honest about this by not pretending otherwise. I have seen the same shape on another financial-services warehouse migration onto AWS: the cutover is a testing problem wearing a data-movement costume.
When DMS is the right tool, and when it is not
DMS earns its place on lift-and-shift into AWS and on cutovers that cannot take downtime. It is not the only option, and for some jobs it is the wrong one.
| Situation | Better fit | Why |
|---|---|---|
| Same-engine move, downtime is acceptable | Native tools (pg_dump/pg_restore, mysqldump) | Simpler, free, and perfectly good for a one-off with a maintenance window. |
| One-shot bulk load into PostgreSQL | pgloader | Purpose-built for exactly this; fast and low-ceremony. |
| Long-lived streaming replication into Kafka | Debezium | An open CDC platform meant to run continuously, not a migration you eventually stop. |
| Cross-engine cutover with minimal downtime | SCT + DMS | This is the sweet spot DMS was built for. |
| Ongoing, high-frequency replication forever | Reconsider | DMS CDC can get expensive and strained as a permanent pipeline; it shines as a migration, not a product. |
A useful gut check: DMS is a migration tool, not a data-integration platform. If the job has an end date, DMS fits. If you are quietly building permanent replication, you are probably reaching for the wrong thing, and the Seattle Data Guy makes the same case about not using it as an ELT engine.
A quick word on cost
DMS pricing rewards short, sharp migrations. Two models matter:
- On-demand replication instances bill for the instance plus log storage. Predictable, and cheaper when a migration runs for weeks.
- DMS Serverless auto-scales capacity and bills by the DCU-hour, which usually wins for shorter runs. The rough crossover is a week or two of active replication: below that, serverless tends to be cheaper; well above it, a right-sized on-demand instance often is.
The bigger cost lesson mirrors the AWS Glue cost story: the meter runs the whole time the task is live, so a migration that drags on because the schema conversion was under-scoped costs you twice. Finish the conversion work first and the data step is short.
How to plan around the gaps
A sequence that keeps the surprises small:
- Classify the migration. Same engine or different? That answer sizes everything else.
- Run SCT early on a heterogeneous move and read the "cannot auto-convert" report. That list is your true scope.
- Inventory the objects DMS skips: indexes, foreign keys, triggers, views, procedures, users. Script their recreation on the target; do not do it by hand at cutover.
- Do a small test migration first. It surfaces privilege gaps, character-set issues and networking problems while they are cheap.
- Full load plus CDC, with alarms on instance memory and storage from the start.
- Validate twice: DMS row validation for the data, your own tests for the logic.
- Cut over against measured lag, not an assumed zero.
Frequently asked questions
Does AWS DMS migrate stored procedures?
No. DMS moves table data and the primary key. Stored procedures, functions, triggers and views are database code, and DMS does not convert or migrate them. For a heterogeneous migration you convert that code with the AWS Schema Conversion Tool (SCT); on a homogeneous migration you recreate or carry the objects separately.
What does AWS DMS not migrate?
Secondary indexes, foreign keys, triggers, views, stored procedures, functions, sequences in some cases, and users, roles and privileges. It creates the target table with columns, data and the primary key only. Everything else is your responsibility to recreate on the target.
What is the difference between AWS DMS and SCT?
SCT converts schema and code from one engine's dialect to another (the structure and logic). DMS moves the actual row data and can keep the target in sync with change data capture. On a cross-engine migration you use SCT first to build and convert the schema, then DMS to move and sync the data.
Does AWS DMS cause downtime?
It does not have to. Running a full load followed by change data capture (CDC) keeps the source live and the target continuously synced, so downtime is limited to a short cutover window. Note that CDC has replication lag, so plan the cutover around the lag you actually measure.
What is the difference between homogeneous and heterogeneous migration?
Homogeneous means the source and target run the same engine (PostgreSQL to PostgreSQL), so no dialect conversion is needed and it is a single step. Heterogeneous means different engines (Oracle to PostgreSQL), which requires converting the schema and code with SCT before DMS moves the data. Heterogeneous migrations are meaningfully more work.
Is AWS DMS Serverless cheaper than on-demand?
For shorter migrations, usually yes. Serverless scales capacity automatically and bills by usage, which wins for runs of up to a week or two. For long-running replication, a right-sized on-demand instance is often cheaper. Match the model to how long the task will actually be live.
The takeaway
AWS DMS is very good at the thing it claims to do: move data between databases without taking the source offline. The mistake is assuming that is the migration. It is one step of it. The indexes, the constraints, the procedures, and the proof that the target is correct are all yours, and on any system with real logic in the database, that work dwarfs the data movement.
Scope the migration around what DMS does not do and it goes smoothly. Scope it around the demo where the rows appear on the target and you will meet the gap at the worst possible time.
If you are staring down a database or warehouse migration and want it planned around the hard 20% rather than the easy 80%, that is the work I do. Or tell me what you are moving and where and I will tell you where the surprises are hiding. For the layers around this one, the cloud data warehouse migration guide covers choosing the target, and AWS Glue cost optimization covers the pipelines you will build once the data lands.
Mirza Hammad Tariq
AWS Data Engineer with 5+ years building production-grade ETL pipelines, cloud data warehouses, and scalable data architectures in Python, SQL, Dagster, and AWS.