Migrating EC2 to Graviton — Real Savings and a Migration Checklist
The single biggest structural lever on instance pricing is migrating to Graviton. Graviton is AWS’s own arm64 CPU line; comparable instances price around 20% below their x86 counterparts, and with performance factored in, the price-performance gap widens to as much as 40% depending on the generation. Where the previous posts cut waste, this one does the same work at a cheaper rate. It’s organized as a checklist answering “can our workload move?”
The generation landscape — what to pick #
As of mid-2026:
| Generation | Representative instances | Status |
|---|---|---|
| Graviton2 | m6g, c6g, r6g, t4g | Mature, cheap baseline |
| Graviton3 | m7g, c7g, r7g | Mature, widely used |
| Graviton4 | m8g, c8g, r8g, x8g | Current mainstream |
| Graviton5 | m9g, m9gd | GA June 2026 (general purpose first); c9g and r9g expected later this year |
Graviton5 is quoted at up to 25% more compute than Graviton4, but for someone starting a migration, generation choice is secondary. The work of moving to arm64 is generation-independent — once you’re on arm64, later generation swaps are just instance type changes. For a new migration, default to the Graviton4 families based on regional availability and price. For burstable dev environments, t4g remains excellent value.
Migration difficulty — how hard it is, workload by workload #
The whole question reduces to one thing: can you produce binaries that run on arm64?
- Easy — interpreted and VM languages: Python, Node.js, Ruby, PHP, and JVM (Java, Kotlin) applications need almost no code changes once the runtime is arm64. Package repositories of current distributions support arm64 as a matter of course.
- Moderate — native dependencies: Python C extensions and Node native modules mostly ship arm64 wheels and prebuilds, but an old pinned version can trip you up. Verify in CI that a rebuild resolves it.
- Verify directly — your own native code, third-party agents: Go and Rust cross-compile easily; for C/C++ using SIMD intrinsics (the AVX families), check the port to NEON/SVE. For third-party binaries like APM and security agents, confirm the vendor’s arm64 support. Major vendors mostly do; the in-house agent that’s been rolling along for years is the usual surprise.
- No-go — x86-only commercial software: if the vendor ships no arm64 build, exclude that workload. You don’t have to move everything.
The migration checklist #
The actual sequence:
- Dependency inventory — list the application’s native dependencies, base images, and installed agents, and confirm arm64 support. If nothing blocks here, half the work is done.
- Multi-architecture image builds — for container workloads, bundle amd64 and arm64 under one tag with
docker buildx; the build process is covered in Docker Advanced #2. Emulated builds on x86 CI runners are slow — arm64-native runners (GitHub Actions arm64 runners, CodeBuild’s Graviton environments) are faster. - Functional and performance validation in staging — beyond functional tests, load-test and compare p99 latency and throughput against the x86 baseline. Usually equal or better, but it varies by workload, so measurement is the standard.
- Canary cutover — mix a few arm64 nodes into the ASG or EKS node group and let them take a slice of real traffic. With multi-architecture images, the orchestrator pulls the right architecture per node on its own. If it holds, raise the ratio to full cutover.
- Extend to managed services — many are easier than EC2. RDS, Aurora, and ElastiCache switch by changing the instance class to a g family (no application changes); Lambda drops execution cost by 20% when the function architecture is set to arm64. Fargate supports arm64 too. Starting here to build confidence is a perfectly sensible sequence.
Traps that catch people #
- Old AMIs and custom AMI pipelines — Packer templates that baked x86 AMIs need arm64 duplicates. Source AMI IDs differ per architecture.
- x86-only wheels pinned in lock files — if the lock file pins x86 wheel hashes, arm64 installs fall back to source builds and get slow or fail. Regenerate as a multi-platform lock.
- Assuming “performance will be the same” — most web and API workloads are equal or better, but a library optimized for x86 SIMD can invert that. Don’t skip the measurement in step 3.
- Image tag mistakes during mixed operation — during the transition, deploying an amd64-only image to an arm64 node is an easy accident. Enforcing multi-architecture manifests by default prevents it.
Computing the savings #
The effect is “rate difference × share migrated.” On-demand rates run around 20% below same-generation x86, and Savings Plans multiply on top. One caution: EC2 Instance Savings Plans are tied to an instance family. If a migration is planned, a commitment that follows you across architectures — Compute Savings Plans — is safer than one that pins the family. Commitment structures are covered in SAA Domain 4-1.
Summary #
- Graviton migration structurally cuts around 20% off comparable x86 rates, and once on arm64, generation swaps (Graviton4 mainstream today, Graviton5 GA) are just type changes.
- The crux is producing arm64 binaries. Interpreted and JVM stacks are easy; native dependencies and third-party agents are the checkpoints.
- The order: dependency inventory → multi-arch images → staging measurements → canary → expand. Don’t skip the measurements.
- RDS, ElastiCache, and Lambda are easier than EC2 — a good place to start building confidence.
- With a migration planned, choose Compute Savings Plans over family-pinned commitments.