Every quarter I review the spend with engineering leads, and every quarter someone asks for "the big cost win." They expect a re-architecture. The actual biggest, lowest-risk win is usually changing one letter in an instance type, moving from m6i to m6g. Graviton, AWS's Arm-based processor line, delivers roughly 20% lower price for comparable or better performance, and most teams simply haven't flipped the switch.

I've migrated a dozen workloads to Graviton now. Here's why it's nearly free money and where the genuine caveats are.

Where the 20% comes from

Graviton instances are priced below their Intel and AMD counterparts while often delivering equal or better throughput per core. The naming is consistent, the g in the family denotes Graviton:

Workloadx86 typeGraviton typeApprox. savings
General purposem6i.xlargem6g.xlarge~20%
Compute optimizedc6i.2xlargec6g.2xlarge~20%
Memory optimizedr6i.larger6g.large~20%

That's before any performance gain. On a steady-state fleet, a clean swap is a 20% line-item reduction with no code change for most managed services.

The managed-service path is almost free

The easiest wins aren't EC2 at all, they're managed services where AWS handles the binaries. RDS, ElastiCache, OpenSearch, and Lambda all offer Graviton options where switching is a configuration change. For Lambda, you set the architecture and that's it:

resource "aws_lambda_function" "worker" {
  function_name = "image-resizer"
  runtime       = "python3.12"
  architectures = ["arm64"]   # Graviton2; default is x86_64
  handler       = "app.handler"
  filename      = "build.zip"
}

For RDS it's a modify-instance operation. There's a short maintenance window, but no application change because the engine is AWS-managed.

The reason most teams leave this money on the table isn't technical difficulty, it's that nobody owns "go change the instance family." Make it a named task with an owner and it gets done in a sprint.

The one real caveat: native dependencies

Graviton is Arm64, not x86. Interpreted code (Python, Node, Java, Go cross-compiled) runs unchanged. The thing that bites you is binary dependencies compiled for x86, a Python wheel with C extensions, a Docker image built FROM an x86 base, a native library without an Arm build. The fix is to build for the right architecture:

docker buildx build --platform linux/arm64 \
  -t 123456789012.dkr.ecr.us-east-1.amazonaws.com/api:arm64 \
  --push .

Multi-arch images via buildx let the same tag serve both architectures during a gradual migration. Most popular images already publish Arm variants; the long tail of internal images is where you'll spend your effort.

Validate, then migrate gradually

I don't flip production in one move. The pattern that's never burned me:

  1. Build an Arm64 image and run the full test suite on a Graviton instance.
  2. Shift a small percentage of traffic via a mixed-instance Auto Scaling group or a canary target group.
  3. Watch latency and error rates for a few days, Arm performance characteristics differ slightly under some memory-bandwidth-bound workloads.
  4. Roll the rest of the fleet and update your Compute Savings Plans, which apply across architectures automatically.

That last point matters: Compute Savings Plans cover Graviton, so you stack the ~20% architecture discount on top of your existing commitment discount rather than choosing between them.

Takeaways

  • Graviton typically cuts compute cost ~20% for equal or better performance, a one-letter instance-type change.
  • Start with managed services (Lambda, RDS, ElastiCache) where switching architecture is just configuration.
  • The only real blocker is x86-compiled binaries; rebuild with docker buildx --platform linux/arm64.
  • Migrate gradually behind a canary, and note that Compute Savings Plans discounts stack on top of the Graviton savings.