← All guides

Right-sizing EC2 with $/vCPU-hr and $/GiB-hr

Published May 5, 2026

Most instance-sizing decisions get made once, in a hurry, by copying whatever size a tutorial or a former coworker used, and never revisited. That’s how a fleet ends up full of xlarge instances running services that peak at 20% CPU and 90% memory, or the reverse. “Bigger = safer” feels like a reasonable hedge against an outage, but it’s just deferred cost with no guarantee it fixes the problem it’s hedging against. An instance sized wrong on vCPUs doesn’t get better by also being wrong on memory.

This guide gives you a method that doesn’t depend on gut feel: measure what your workload actually needs, price it in $/vCPU-hr and $/GiB-hr, and compare that number across sizes and families using the instance explorer and comparison tool.

The two numbers, and what each one tells you

Every instance detail page on this site (see any instance page, e.g. m7i.xlarge) shows two efficiency figures under “Cost per vCPU-hr” and “Cost per GiB-hr.” Both are computed the same simple way:

Neither number is “the” efficiency metric. They measure different things, and which one matters depends on what your workload is actually bottlenecked on:

Most real services aren’t bound by just one of these, which is why you need both numbers rather than only comparing hourly prices. An instance can look cheap on the sticker and still be the wrong shape for what you’re running.

Is bigger actually more expensive per unit? Checking AWS’s own pricing

The instinct behind “just size up for headroom” assumes going bigger is roughly neutral on a per-unit basis. That’s worth checking against real numbers instead of assuming it. Here’s the general-purpose m7i family across its full size range, us-east-1, Linux, on-demand:

Size vCPU Memory (GiB) Price/hr $/vCPU-hr $/GiB-hr
m7i.large 2 8 $0.1008 $0.05040 $0.01260
m7i.xlarge 4 16 $0.2016 $0.05040 $0.01260
m7i.2xlarge 8 32 $0.4032 $0.05040 $0.01260
m7i.4xlarge 16 64 $0.8064 $0.05040 $0.01260
m7i.8xlarge 32 128 $1.6128 $0.05040 $0.01260
m7i.16xlarge 64 256 $3.2256 $0.05040 $0.01260
m7i.24xlarge 96 384 $4.8384 $0.05040 $0.01260
m7i.48xlarge 192 768 $9.6768 $0.05040 $0.01260

The $/vCPU-hr and $/GiB-hr columns don’t move, from large to 48xlarge, a 96x jump in vCPU count. The price scales exactly linearly. The same holds in m7g ($0.04080/vCPU-hr flat), c7i ($0.04462/vCPU-hr flat), c7g (roughly $0.0362 to $0.0363/vCPU-hr, flat within rounding), and r7i ($0.06615/vCPU-hr flat). We checked all of them against the pricing data rather than assuming the pattern from one family.

Within a family, AWS gives you neither a bulk discount for buying a bigger box nor a premium for consolidating. A 4xlarge costs exactly 4x an xlarge, unit for unit. Two consequences follow:

  1. There’s no pricing reward for over-provisioning “to be safe.” Sizing up from what you need to double what you need doubles your bill with mathematical precision. It isn’t cushioned by an economy-of-scale discount, because that discount doesn’t exist.
  2. There’s no pricing penalty for splitting one big instance into several smaller ones, either. If a workload can be horizontally scaled, four xlarge instances cost the same as one 4xlarge. Make that call on operational grounds (blast radius, autoscaling granularity, bin-packing), not cost, because cost is a wash.

The number that actually moves is which family and generation you pick, not which size within a family.

Cross-family comparison: the real lever

Since within-family efficiency is flat, the decision that matters is which family shape fits your workload. Compare three families at the same vCPU count: 8 vCPUs, us-east-1, Linux, on-demand.

Instance vCPU Memory (GiB) Price/hr $/vCPU-hr $/GiB-hr
c7i.2xlarge (compute) 8 16 $0.3570 $0.04462 $0.02231
m7i.2xlarge (general purpose) 8 32 $0.4032 $0.05040 $0.01260
r7i.2xlarge (memory) 8 64 $0.5292 $0.06615 $0.00827

Same vCPU count, three different machines. c7i is the cheapest compute in this comparison, 12% cheaper per vCPU than m7i and 33% cheaper than r7i, but it carries the least memory, so its $/GiB-hr is the worst of the three. r7i flips that: worst $/vCPU-hr (48% more than c7i), but by far the best $/GiB-hr, at less than half of c7i’s. m7i sits in the middle on both, which is exactly what “general purpose” is supposed to mean, and exactly why it’s the wrong default when a workload leans clearly one way.

This is where “just pick the popular general-purpose size” costs real money. A memory-bound cache running on m7i is paying $0.05040/vCPU-hr for vCPUs it isn’t using, to get to memory that r7i sells more cheaply. It should be on r7i. A stateless compute-bound worker running on m7i is paying for 32 GiB of memory headroom it never touches, when c7i would give it more compute per dollar and less wasted RAM. Neither instance is wrong on size. Both are the wrong shape.

A method for right-sizing

Two facts are now established: size doesn’t change unit economics, family shape does. Here’s a repeatable process built on them.

  1. Baseline your current utilization. Pull actual CPU and memory utilization for the workload over at least a week, capturing peak periods, not just averages. If you don’t have this instrumented yet, that’s the real first step. Sizing decisions made without utilization data are just guesses with better production values.
  2. Translate utilization into a vCPU/memory target. Take your peak (not average) CPU and memory usage, add a safety margin sized to your workload’s actual volatility rather than a blanket 2x, and convert to a vCPU and GiB target. This is the size you need, not the size you currently have.
  3. Check which shape your workload has. Compute your current memory-to-vCPU ratio (GiB per vCPU) and compare it to what each family offers: compute-optimized families run lean on memory per vCPU, memory-optimized families run rich, general-purpose sits in between. If your target ratio doesn’t match your current family’s ratio, that mismatch is costing you.
  4. Compare $/vCPU-hr or $/GiB-hr across families at your target size, using whichever metric matches the bottleneck you identified in step 3. Look up candidates on the instance explorer, which shows both figures for every instance type, then use the comparison tool to line up two or three finalists side by side: vCPU, memory, network, and price together.
  5. Check the family page for your shortlist, e.g. families/m7g or families/c7i, to confirm generation and architecture. If arm64 is on the table, read Graviton vs. x86 first, since switching architecture can move the price further than switching within x86.
  6. Verify with a real deployment, not just the spec sheet. Run the candidate size in staging or as a canary against production traffic for long enough to see peak load, then check whether utilization landed where you predicted. If CPU or memory is still pinned at the new size, the mismatch was bigger than the baseline data suggested; go up a size or across to a different family before assuming the metrics were wrong.

Re-run this whenever a workload’s traffic profile changes meaningfully, not just once at launch. A service sized correctly at launch drifts out of shape as usage patterns change. The instance never resizes itself.

Making the call

Compute-bound, low memory footprint: batch processing, video transcoding, request routing, anything where CPU% tracks load and memory stays flat. Compare on $/vCPU-hr and look at compute-optimized families first. They’ll usually win on that metric, and you stop paying for memory you don’t use.

Memory-bound, low CPU footprint: caches, in-memory stores, large-heap JVM services, anything sized by RSS rather than load. Compare on $/GiB-hr and look at memory-optimized families first. The per-vCPU premium is worth it because vCPUs aren’t the constraint.

Genuinely balanced, or you haven’t measured yet: general-purpose families are a reasonable starting point, but treat them as a starting point, not a permanent home. Once you have real utilization data, re-run the comparison. Most workloads turn out to lean one way once you actually look.

Bottom line: within a family, size is a wash. AWS’s own pricing scales perfectly linearly, so there’s no cost reward for over-provisioning and no cost penalty for right-sizing down. The only lever that changes your unit economics is picking the family whose vCPU-to-memory ratio matches your workload’s actual bottleneck. Measure that bottleneck, then let $/vCPU-hr or $/GiB-hr, not habit, pick the family and size.