gp2 vs gp3 cost savings¶
gp3 is faster, more flexible, and 20% cheaper per GB-month than gp2. There is no reason for new volumes to be created as gp2, and there is almost no reason for existing gp2 volumes to stay that way. This guide walks through the price math, the IOPS / throughput differences, and the online migration.
Run the gp2 → gp3 calculator →
The price math¶
| Volume type | $/GB-month (us-east-1) | Baseline IOPS | Baseline throughput |
|---|---|---|---|
| gp2 | $0.10 | 3 IOPS/GB (min 100, burst to 3,000) | 250 MB/s max |
| gp3 | $0.08 | 3,000 IOPS flat | 125 MB/s flat |
The gp3 baseline is better than what a 1 TB gp2 volume bursts to. Anything under 1 TB on gp2 is paying gp2 prices for worse sustained IOPS than gp3 provides as the floor.
The 20% rule of thumb: for every 5 TB of gp2 you migrate, you save ~$1,200/year. The math is linear:
For 5,000 GB → 5,000 × $0.24 = $1,200/yr.
Why teams haven't already done this¶
The migration was straightforward from day one of gp3 (Dec 2020) but it kept getting pushed because:
- "It can't be this simple." Teams assume there's a tradeoff. There isn't, for ~95% of workloads.
- "What if we need the gp2 burst behaviour?" gp3's baseline 3,000 IOPS is higher than gp2's burst on a sub-1-TB volume. The bursting argument inverts on small volumes.
- "What if it's slow during the migration?" AWS
ModifyVolumeis online. The IOPS are gradually rebuilt in the background; the workload doesn't see a stop.
How ModifyVolume actually works¶
When you change a volume type, AWS runs the migration in the background. The volume reports a state: modifying in the EC2 API while it's working, and a state: completed when it's done. Throughout:
- The workload keeps reading and writing — no remount, no fsfreeze, no signal to the application.
- Performance during the migration is at the slower of the two configurations. For gp2 → gp3 specifically, the practical effect is: same gp2 perf for a few hours, then gp3 perf.
- You can monitor progress via the EC2 console "Modifications" tab or
aws ec2 describe-volumes-modifications.
The migration is idempotent — re-running it on an already-converted volume returns immediately with optimizing or completed.
When you need more than gp3's baseline¶
For databases doing >3,000 sustained IOPS or >125 MB/s sustained throughput, gp3 lets you provision extra at marginal cost:
| Extra | Rate |
|---|---|
| Extra IOPS (above 3,000, up to 16,000) | $0.005/IOPS-month |
| Extra throughput (above 125 MB/s, up to 1,000 MB/s) | $0.04/MB/s-month |
Even with significant extra IOPS provisioned, gp3 typically beats gp2 and io1. The exception is workloads needing >16,000 IOPS or >1,000 MB/s — those should be on io2 for the durability + performance guarantees.
Worked example¶
A startup with 5 TB (5,000 GB) of gp2 volumes across RDS, EC2, and self-managed databases:
5,000 × $0.10 = $500/mo on gp2
5,000 × $0.08 = $400/mo on gp3
────────
Monthly savings = $100/mo
Annual savings = $1,200/yr (20% cut on the EBS line)
The migration is online (one aws ec2 modify-volume per volume) and the SLA tier improves at the same time (gp3 has higher sustained performance than gp2 for under-1-TB volumes).
How to migrate without breaking anything¶
Step 1: audit your gp2 footprint¶
aws ec2 describe-volumes \
--filters 'Name=volume-type,Values=gp2' \
--query 'Volumes[].{Id:VolumeId,Size:Size,Iops:Iops,Throughput:Throughput,State:State,Attached:Attachments[0].InstanceId}' \
--output table
Note the volumes with Attached: None — those are unattached and shouldn't be migrated. They should be deleted instead (after a snapshot).
Step 2: identify the volumes that need extra IOPS / throughput¶
For each volume with Iops > 3000, decide whether the gp2 burst behaviour was actually being hit:
aws cloudwatch get-metric-statistics \
--namespace AWS/EBS \
--metric-name VolumeReadOps \
--dimensions Name=VolumeId,Value=vol-... \
--start-time $(date -u -v-7d '+%Y-%m-%dT%H:%M:%S') \
--end-time $(date -u '+%Y-%m-%dT%H:%M:%S') \
--period 3600 --statistics Maximum
If the volume sustained more than ~3,000 IOPS for any meaningful window, plan to provision extra gp3 IOPS to match.
Step 3: roll out in waves¶
- Dev / staging volumes first. Migrate them, watch CloudWatch IOPS + throughput for a week. They should look identical or better.
- Then production replicas / standbys. Migrate the read replica before the primary so you can fail over if needed.
- Then production primaries. No downtime, but pick a low-traffic window in case the host needs to rebalance after the modification.
Step 4: prevent the regression¶
Set a tagging policy / Service Control Policy so new volumes default to gp3:
{
"Statement": [{
"Effect": "Deny",
"Action": "ec2:CreateVolume",
"Resource": "arn:aws:ec2:*:*:volume/*",
"Condition": {
"StringEquals": { "ec2:VolumeType": "gp2" }
}
}]
}
Otherwise teams will keep creating gp2 by reflex.
Where to go next¶
- Run the gp2 → gp3 calculator with your total provisioned GB to see exact monthly and annual savings.
- Look at the Cloud Waste Radar for the rest of your EBS footprint (unattached volumes, old snapshots).
- Cross-link: gp2 → gp3 is one of twelve quick wins in the startup checklist.
Want a verified savings number?¶
Book a free 30-minute audit and we'll go through your EBS footprint, tag the migration candidates by dollar size, and produce a Terraform PR that does the modify-volume calls in a controlled rollout.