gp2 to gp3: migrate EBS volumes and cut storage cost 20%
gp3 costs 20% less per GiB than gp2 and includes a 3,000 IOPS baseline. How to check which volumes can move, and migrate them online.
Contents
In short
- gp3 costs 20% less per GiB than gp2.
- Its baseline of 3,000 IOPS and 125 MB/s matches any gp2 volume up to 170 GiB; measure bigger ones first.
- The change is online: no detach, no restart.
gp3 is the current general purpose SSD volume type on EBS. It costs 20% less per GiB than gp2 and includes 3,000 IOPS and 125 MB/s whatever its size. The switch happens online, with Elastic Volumes: no detach, no restart, no new volume.
For most volumes it’s one command. Large or busy volumes need a check first, because gp2’s performance grows with its size and gp3’s doesn’t. This guide covers both.
The price difference
In us-east-1, as of October 2026 (EBS pricing):
| gp2 | gp3 | |
|---|---|---|
| Storage | $0.10 per GB-month | $0.08 per GB-month |
| IOPS | 3 per GiB, small volumes burst to 3,000 | 3,000 included |
| Throughput | Grows with size | 125 MB/s included |
| More performance | Only by growing the volume | $0.005 per extra IOPS-month, $0.06 per extra MB/s-month |
A 500 GiB volume drops from $50.00 to $40.00 a month. A 1,024 GiB volume drops from $102.40 to $81.92. Modifying a volume is free (Elastic Volumes), so the move itself costs nothing.
Find your gp2 volumes
List them region by region, with the instance each one is attached to:
for r in $(aws ec2 describe-regions --query 'Regions[].RegionName' --output text); do
echo "== $r"
aws ec2 describe-volumes --region "$r" --filters Name=volume-type,Values=gp2 \
--query 'Volumes[].[VolumeId,Size,State,Attachments[0].InstanceId]' --output table
done
To size the prize in one region, add up the GiB. Each GiB you move saves $0.02 a month:
aws ec2 describe-volumes --region us-east-1 --filters Name=volume-type,Values=gp2 \
--query 'sum(Volumes[].Size)'
Volumes in the available state are attached to nothing. Don’t migrate those: delete them.
Check IOPS and throughput on big or busy volumes
gp2 gives a volume 3 IOPS per GiB. Small volumes can burst to 3,000 IOPS on credits, and above 1,000 GiB the baseline itself passes 3,000: a 2,000 GiB gp2 volume has 6,000 IOPS all the time. Throughput also grows on large gp2 volumes. gp3 starts at 3,000 IOPS and 125 MB/s for any size and bills anything more.
If you change the type without saying what you want, AWS gives the volume the higher of its gp2-equivalent performance or the gp3 baseline (Elastic Volumes). That’s safe, but on a big volume you then pay for performance it may never use. A 2,000 GiB volume would cost $160 for storage plus 3,000 extra IOPS at $0.005 each, $15, before any extra throughput: $175 or more instead of $200, where $160 was possible.
So measure first. This reads two weeks of a volume’s real IOPS from CloudWatch, in 5-minute periods, and prints the peak:
aws cloudwatch get-metric-data --region us-east-1 \
--start-time 2026-09-27T00:00:00Z --end-time 2026-10-11T00:00:00Z \
--metric-data-queries '[
{"Id":"r","ReturnData":false,"MetricStat":{"Period":300,"Stat":"Sum","Metric":{
"Namespace":"AWS/EBS","MetricName":"VolumeReadOps",
"Dimensions":[{"Name":"VolumeId","Value":"vol-0b9e4c6a12"}]}}},
{"Id":"w","ReturnData":false,"MetricStat":{"Period":300,"Stat":"Sum","Metric":{
"Namespace":"AWS/EBS","MetricName":"VolumeWriteOps",
"Dimensions":[{"Name":"VolumeId","Value":"vol-0b9e4c6a12"}]}}},
{"Id":"iops","Expression":"(r+w)/PERIOD(r)","Label":"IOPS"}]' \
--query 'max(MetricDataResults[0].Values)'
For throughput, run it again with VolumeReadBytes and VolumeWriteBytes and the expression (r+w)/PERIOD(r)/1048576, which gives MiB/s.
A 5-minute average smooths out short spikes, so leave headroom, and check the application’s own latency graphs for the same weeks. Then decide:
- Peak under 3,000 IOPS and 125 MB/s: move it to plain gp3 and say so explicitly, so it doesn’t inherit gp2-sized performance.
- Peak above that: set IOPS and throughput to the peak plus headroom. It’s usually still cheaper than gp2.
Migrate
One volume, with the performance set explicitly:
aws ec2 modify-volume --region us-east-1 --volume-id vol-0b9e4c6a12 \
--volume-type gp3 --iops 3000 --throughput 125
aws ec2 describe-volumes-modifications --region us-east-1 --volume-ids vol-0b9e4c6a12 \
--query 'VolumesModifications[0].[ModificationState,Progress]' --output text
The modification goes from modifying to optimizing to completed, and the volume keeps serving reads and writes the whole time. AWS notes a 1 TiB volume can take up to 6 hours. Instances of previous generations may need the volume detached or the instance stopped (Elastic Volumes).
Every attached gp2 volume of 170 GiB or less in a region, at the gp3 baseline. Up to that size, gp2 delivers no more than 3,000 IOPS and 128 MiB/s, so the gp3 baseline matches it:
for v in $(aws ec2 describe-volumes --region us-east-1 \
--filters Name=volume-type,Values=gp2 Name=status,Values=in-use \
--query 'Volumes[?Size<=`170`].VolumeId' --output text); do
aws ec2 modify-volume --region us-east-1 --volume-id "$v" \
--volume-type gp3 --iops 3000 --throughput 125 \
--query 'VolumeModification.ModificationState' --output text
done
Bigger gp2 volumes can burst to or sustain 250 MiB/s, and from 1,000 GiB they get more than 3,000 IOPS. Run the IOPS and throughput check above on each of those, and set --iops and --throughput to match what it shows (gp2 performance).
If you need to go back
A volume accepts a limited number of modifications: AWS allows 4 in a rolling 24 hours (Elastic Volumes). If a workload slows down after the move, the usual fix isn’t gp2 again but more IOPS or throughput on gp3, which is the same command with higher numbers. Changing back to gp2 is possible once the modification has completed.
Keep new volumes on gp3
The gp2 volumes you just moved will come back if the things that create volumes still ask for gp2.
- Launch templates and block device mappings: set
"VolumeType": "gp3", including for the root volume. An AMI registered with a gp2 root mapping gives every new instance a gp2 root unless the launch template overrides it. - Infrastructure code: set the volume type explicitly instead of relying on defaults.
- Automation: Compute Optimizer automation rules can upgrade volume types on a schedule once you turn them on.
Omni FinOps lists every attached gp2 volume as a lead on each refresh, with its monthly saving and the modify-volume command. Snapshots aren’t affected by the change: they’re priced the same whichever type the volume was. When storage is done, the next easy saving in the same place is old snapshots.
Mateo Vargas writes Omni FinOps’ cost guides, from the same rules the product runs on every refresh. Prices are list prices in us-east-1 or us-central1 as of October 11, 2026; check your region’s pricing page.