Guides · Guide · 12 min read · Jul 7, 2026

The AWS Migration Checklist (That Actually Prevents Outages)

Most AWS migrations don’t fail because of AWS. They fail because someone flipped DNS before the data finished replicating, or because a dependency nobody had mapped was still pointing at the old datacenter. This is the AWS migration checklist we run ourselves — six phases, each with exit criteria, designed so no step is irreversible.

First: pick the right “R” for each workload

AWS’s standard framing is the 6 Rs — apply it per workload, not per company:

  • Rehost (lift-and-shift): move the VM as-is. Fastest, lowest risk, zero modernization.
  • Replatform (lift-and-reshape): small swaps on the way — self-managed Postgres to RDS, homegrown queue to SQS. Usually the best effort-to-value ratio.
  • Repurchase: drop the self-hosted thing entirely and buy SaaS (Jira, GitLab, monitoring).
  • Refactor: rearchitect for cloud-native (containers, serverless, managed data stores). Highest value, highest cost — reserve it for the workloads that earn it.
  • Retire: discovery always finds servers nobody can explain. Turn them off before you pay to move them.
  • Retain: some things stay put — licensing, latency, compliance, or “it’s being decommissioned next year anyway.”

The trap is defaulting everything to rehost. A pure lift-and-shift faithfully copies your waste — oversized VMs, orphaned services, snowflake configs — now billed by the hour. You don’t need to refactor everything either: write the chosen R next to each workload and let boring apps be boring.

Phase 1 — Discovery and assessment (before you touch anything)

Outages during migration are almost always a discovery failure surfacing late. Do the unglamorous inventory work first:

  1. Inventory every application — owner, runtime, OS, criticality, and the chosen R. Tools like AWS Application Discovery Service help, but a spreadsheet built by interviewing teams catches what agents miss.
  2. Inventory every data store — engine, version, size, growth rate, and how much downtime its consumers can tolerate. This drives your replication strategy later.
  3. Map dependencies — what calls what, over which ports, at what volume. Pull real connection data (netstat, VPC-flow-style captures, APM traces), not just tribal knowledge. The dependency you didn’t map is the outage you will have.
  4. Baseline traffic and performance — p50/p95 latency, peak RPS, batch windows. You can’t declare success without a “before.”
  5. Define success criteria in writing — error rate, latency, and data integrity checks that must hold post-cutover.
  6. Write the rollback plan now, per workload, before any work starts. If you can’t articulate how you’d go back, you’re not ready to go forward.
Exit criteria: every workload has an owner, an R, mapped dependencies, success criteria, and a rollback plan. No exceptions for “simple” apps.

Phase 2 — Build the landing zone (as code)

The landing zone is the foundation everything lands on. Getting it right up front is far cheaper than retrofitting guardrails onto a live environment:

  • Account structure — AWS Organizations with multiple accounts: at minimum separate production, non-production, security/logging, and a shared-services account. Accounts are the strongest blast-radius boundary AWS gives you; use them.
  • Networking — VPCs with CIDR ranges that don’t collide with on-prem (you’ll need connectivity during migration), public/private subnet tiers across availability zones, and Transit Gateway connecting the VPCs and your VPN or Direct Connect link back to the source.
  • IAM least-privilege — roles per workload, no long-lived access keys, SSO for humans. Humans assume roles; machines get instance profiles or IRSA.
  • Guardrails — Service Control Policies (SCPs) that deny disasters outright: no leaving approved regions, no disabling CloudTrail, no deleting the logging buckets.
  • Logging from day one — organization-wide CloudTrail into a locked-down account, VPC Flow Logs, AWS Config. You want the audit trail before workloads arrive, not after an incident.

All of this should be Terraform (or equivalent) from the first commit. A hand-built landing zone becomes an unreproducible snowflake within a month, and you lose the ability to stamp out a staging copy of your own foundation.

Phase 3 — Build the target in parallel

The core outage-prevention move: stand up the complete destination environment alongside the source, with zero production impact. Nothing in this phase touches the systems your users depend on.

  1. Provision the target stack as code — compute, load balancers, managed services — in the landing zone.
  2. Deploy the applications via the same CI/CD you’ll use afterwards — don’t carry a manual deploy process across.
  3. Start continuous data replication. For databases, AWS Database Migration Service (DMS) does an initial full load, then change data capture (CDC) keeps the target in sync. For files, DataSync or S3 replication. For queues, dual-write or drain-and-redirect strategies.
  4. Let replication run for days, not hours. Watch DMS task metrics — especially replication latency — until lag is consistently near zero through your peak windows.

Because the source is untouched, this phase carries no user-facing risk — take as long as validation requires.

Phase 4 — Data reconciliation and validation

“The data looks fine” is not a validation strategy. Verify mechanically:

  • Row counts per table, source vs target, at a consistent point in time.
  • Checksums or aggregates on critical columns (sums of balances, max IDs, hash samples) — row counts alone miss corrupted or truncated values.
  • Schema drift — indexes, constraints, sequences, and collations often don’t replicate the way table data does. Compare them explicitly.
  • Run the application against the new stack — full integration and smoke suites, plus a load test replaying production-shaped traffic against your Phase 1 baseline.
  • Rehearse the rollback — actually execute it once in staging. An untested rollback plan is a document, not a plan.
-- Quick reconciliation pass, run on both sides:
SELECT 'orders' AS t, COUNT(*), MAX(id), SUM(total_cents) FROM orders
UNION ALL
SELECT 'users', COUNT(*), MAX(id), NULL FROM users;

Phase 5 — Cutover (staged, at the edge, reversible)

Never a big-bang flip. Cut over at the edge, where you can shift traffic gradually and shift it back in seconds:

  1. Lower DNS TTLs to 60s at least a week ahead, so caches expire before you need them to.
  2. Use weighted routing (Route 53 weighted records or a traffic-shifting load balancer): 5% to the new stack, then 25%, 50%, 100% — with a soak at each step.
  3. Watch the golden signals at every step — latency, traffic, errors, saturation — on both stacks, compared against the Phase 1 baseline. Pre-agree the abort thresholds so the 2 a.m. decision is mechanical, not a debate.
  4. Keep the old stack warm. It runs, fully capable of taking 100% of traffic back, for the entire cutover and the soak after it. Rollback should mean shifting weights back, nothing more.
  5. Mind the writes. Once writes land on the new database, rolling back means replicating backwards. Set up reverse replication (DMS runs the other way too) before you shift write traffic, or plan a short write-freeze window for the final switch.

Phase 6 — Optimize, then decommission

  1. Soak first. Run at 100% for an agreed period — two to four weeks covering at least one month-end or peak cycle — with no regressions against your success criteria.
  2. Right-size. Rehosted workloads are almost always oversized. Use utilization data and Compute Optimizer to shrink instances, then buy Savings Plans for the steady state.
  3. Add elasticity — Auto Scaling groups, scheduled scaling for known cycles. This is the payoff lift-and-shift skipped.
  4. Only then decommission — archive final backups per your retention policy, tear down the old environment, cancel the contracts, and scrub the old stack from runbooks and on-call docs.

The gotchas that cause the 2 a.m. pages

  • Data egress costs — data into AWS is free; out of it isn’t. Hybrid phases where on-prem services chattily call AWS (or vice versa) generate surprising transfer bills. Model the in-between state, not just the end state.
  • DNS TTLs — some resolvers and Java runtimes ignore TTLs and cache addresses indefinitely. Expect stragglers hitting the old stack for days; keep it answering.
  • Hardcoded IPs — grep every codebase and config store for the old environment’s ranges before cutover. Connection strings, firewall rules, and “temporary” scripts hide them.
  • Licensing — some vendor licenses are tied to physical cores or MAC addresses, or forbid cloud deployment outright. Check before the workload is in flight.
  • Hidden dependencies — the cron job on a forgotten box, the reporting tool reading a replica directly, the partner with your old IP allowlisted. Phase 1 rigor is the only defense.
  • Timezone and locale — old servers often run in local time; AWS instances default to UTC. Batch schedules, log timestamps, date-boundary logic, and database collations all shift.
  • Security groups are not your old firewall — they’re stateful, default-deny inbound, and per-interface. Translating a flat legacy ruleset one-to-one leaves things too open or silently blocks a needed flow. Rebuild rules from the Phase 1 dependency map.

The short version

Choose an R per workload. Discover before you design. Build the landing zone as code. Stand up the target in parallel, replicate continuously, and validate mechanically. Cut over in stages with the old stack warm; optimize, soak, then decommission. Every step stays reversible until the soak is done — that’s what actually prevents outages.

If you’d rather run this with people who have executed it many times, our cloud migration services cover the full checklist end to end, and our infrastructure as code practice builds the landing zone and target environment as Terraform from the first commit.

AWSCloud MigrationTerraform

Need this done, not just read about?

Deplyra builds, ships and runs exactly this in production — as code, with GitOps, handed over documented.

Start a project →
Keep reading

Let's build something that stays up.

One message. We'll reply with questions, not a sales pitch — then a plan you can hold us to.

REMOTE WORLDWIDE · FREELANCE / CONTRACT · START: IMMEDIATE