Why this matters
Most EC2 instances get their size once, at launch, and keep it for years. Someone picks a type that feels safe, adds headroom for a busy week, and the choice becomes the default. Meanwhile the workload changes: a cache absorbs read traffic, a new build uses less memory, a batch job moves to a queue. The instance keeps its old shape and you keep paying for headroom nobody uses.
Rightsizing means matching four things at once: the instance family, the size, the generation and the purchase model. A c5.large and an m7g.large are not interchangeable, but a newer generation of the same family often does more work per hour than the old one. Moving to Graviton types such as m7g or c7g can cut cost further, but only if your build produces arm64 artifacts and every dependency supports it.
The hard part is peaks. A server at low average CPU can still need every core at Monday 9am or during a month-end batch. Size against the high percentile of real usage, not the average, and leave room for failover: if one instance dies and its partner takes the load, both need headroom. What you settle on also shapes purchasing, because every size you fix changes what you should commit to with Savings Plans or Reserved Instances.
Before you start
You need three things before you touch anything: CloudWatch read access, EC2 describe permissions, and someone who can change instance types. Compute Optimizer is opt-in, so confirm it is enabled in each account and Region you care about.
Give yourself a data window that covers the boring weeks and the ugly ones. Two weeks is a minimum, four is better, and the window should include month-end batches, deploy days and seasonal peaks. Basic CloudWatch metrics arrive every five minutes, which is fine for trends. Detailed monitoring gives one-minute data at an extra charge and is worth it for spiky services.
Default EC2 metrics do not include memory. Install the CloudWatch agent and publish mem_used_percent and disk usage, or you will guess on every memory-bound workload. For containers, pull memory from Container Insights rather than inferring it from CPU.
Know what a resize costs in change terms. Resizing an EBS-backed instance means stop, change type, start: a few minutes of downtime and a new public IP unless you use an Elastic IP. Instance store data does not survive a stop. Some software is tied to a host or MAC address. If the instance belongs to an Auto Scaling group or an EKS managed node group, you change the launch template, not the instance.
How to do it
Work in one direction: inventory, measure, decide, change, verify. Keep sizing and purchasing in separate steps, or you will not know which change produced the result.
Compute Optimizer gives over-provisioned and under-provisioned findings with a risk rating, and it is a useful first pass. It only sees the metrics it receives, and it does not know about licenses, failover design or the batch that runs on the first of the month. Treat its output as a candidate list, not a decision.
- Tag and inventory every instance. Pull a list per account and Region with instance ID, type, launch date, tags, Auto Scaling group and environment. Anything untagged gets an owner before it gets a new size. You cannot rightsize what you cannot attribute.
- Publish memory and disk metrics. Install the CloudWatch agent through Systems Manager or your image pipeline, then confirm mem_used_percent appears in CloudWatch. Without memory data, memory-bound instances are invisible and downsizing them is a gamble.
- Set a utilization target and read percentiles. Decide the ceiling you will size to, such as 60 to 70 percent p95 CPU and under 80 percent peak memory on steady services, and write it down so two engineers reach the same answer. Graph CPUUtilization, mem_used_percent, network and EBS throughput across the full window, then note the peak day and its cause.
- Check burstable credit behavior. For T3 and T4g instances, look at CPUCreditBalance and CPUSurplusCreditCharge over the window. A balance that sits near zero means the instance runs above baseline, and a smaller burstable type will throttle.
- Check the limits that are not CPU. Network baseline bandwidth, EBS throughput and IOPS, and attached ENI count all scale with instance size. A workload that idles on CPU but pushes heavy traffic or disk I/O can get worse when you shrink it.
- Pick the target family and generation. Move to the newest generation your images and agents support, and consider Graviton only when you have an arm64 build path. Compare like for like on vCPU, memory, network and EBS limits, not just the instance name.
- Test on a clone. Launch a test instance from the same AMI and launch template with the target type, replay representative traffic or run your load test, and watch latency and error rate. Teams that skip this find the problem in production instead.
- Apply the change and record it. Resize in a change window with a rollback plan, or roll a new launch template through the Auto Scaling group. Log the old type, new type, reason and date in your inventory so the next review has history.
How to check it worked
Compare the same metric window before and after. For a healthy resize, p95 CPU rises and stays under your ceiling, peak memory stays below your limit, and little else moves. Look at the first full week after the change, not the first hour.
Then check what CPU does not show: request latency, 5xx rate, queue depth, EBS BurstBalance, CPU credit balance on T instances, and dropped packets. A resize that saves cost but pushes latency past your service target is not a win.
On the cost side, group Cost Explorer by instance type and check the Cost and Usage Report for line item detail. Give it a week, since billing data lags and partial days confuse the picture. Compare the new type against the old one on the same workload, not across the whole account.
Set a recheck date 30 days out. Traffic shifts, deploys change memory use, and a size that was right in March may be wrong in June. Repeat the review quarterly and after any large release.
Mistakes to avoid
Downsizing on averages is the most common error. A weekly average hides the Monday spike and the first-of-month batch, and the next spike after the change shows you the gap in production.
Watch the burstable trap. T3 and T4g instances earn credits at a baseline tied to size. If a workload sits near baseline all day, a smaller T type will spend time throttled to its baseline, and surplus credits add cost. If usage is steady and above baseline, a fixed performance family usually fits better. Check CPUCreditBalance and CPUSurplusCreditCharge before you shrink one.
Do not change only the CPU number. Network bandwidth, EBS throughput, EBS IOPS and ENI limits shrink with instance size, so a smaller box can hit a bandwidth ceiling before a CPU ceiling. Check license terms and host-bound software too, and remember that a stop and start changes the public IP unless it is an Elastic IP.
Finally, do not treat rightsizing as a one-time project, and do not buy commitments before you finish. Sizes change, and commitments should follow the shape you settle on. If you want an outside read first, the Cloudverg Cloud cost audit is a two-week, read-only review of up to three accounts with rightsizing findings, a commitment plan and a ranked savings report, at a fixed price.
Frequently asked questions
How often should I rightsize EC2 instances?
Review steady workloads quarterly, and again after a major release or a traffic shift. Compute Optimizer refreshes recommendations daily, so a monthly skim of its findings catches drift between full reviews.
Does resizing an EC2 instance cause downtime?
For EBS-backed instances, yes, because you must stop the instance before changing its type. Expect a few minutes of downtime, a new public IP unless you use an Elastic IP, and loss of any instance store data. Auto Scaling groups avoid this by rolling new instances from an updated launch template.
Can I rightsize without memory metrics from CloudWatch?
You can for CPU-bound services, but memory-bound workloads need real memory data or you risk out-of-memory crashes. Use the CloudWatch agent, Container Insights for containers, or an existing monitoring agent that already publishes to CloudWatch.