The gp2 to gp3 storage tax: why millions of volumes never migrated
In December 2020, AWS introduced gp3, a next-generation General Purpose SSD volume type for Amazon EBS. The headline was simple: a flat 20% discount on storage ($0.08/GB-month vs $0.10/GB-month in us-east-1) and the decoupling of IOPS and throughput from volume size.
Years later, audit any medium or large AWS organization and you will find hundreds or thousands of active gp2 volumes quietly incurring unnecessary costs.
Understanding why this migration remains incomplete requires examining the math of EBS burst buckets, the billing mechanics of decoupled performance, and the economics of cloud provider defaults.
The gp2 design: coupled scaling and burst buckets
When AWS launched gp2 in 2014, flash storage was expensive and provisioning controls were primitive. AWS designed gp2 around a linear coupling model: volume capacity dictated performance.
Every gigabyte allocated on gp2 provided 3 baseline IOPS:
- A 100 GB root disk got 300 baseline IOPS.
- A 500 GB database volume got 1,500 baseline IOPS.
- Maxing out gp2 at 16,000 IOPS required provisioning 5,334 GB (5.33 TiB), whether the application needed 5 TB of storage or 500 GB.
gp2 Baseline IOPS = Size in GB × 3 (min 100, max 16,000)
To prevent small volumes from stalling during operating system boot or package installations, AWS wrapped gp2 in an I/O credit burst bucket. Volumes under 1,000 GB started with 5.4 million I/O credits, allowing them to burst up to 3,000 IOPS for up to 30 minutes.
When the burst bucket emptied under sustained load, the volume dropped to its baseline rate (3 IOPS per GB). A 50 GB volume suddenly fell to 150 IOPS, causing unexplained I/O wait spikes, database lockups, and degraded application response times.
Throughput suffered from similar coupling. gp2 offered throughput between 128 MB/s and 250 MB/s, but only volumes larger than 334 GB could sustain the 250 MB/s ceiling.
How gp3 changed the equation
gp3 eliminated the burst bucket and decoupled performance provisioning from drive size.
Every gp3 volume, from a 1 GB scratch disk to a 16 TB file store, includes a guaranteed baseline:
- Storage: $0.0800/GB-month (20% less than gp2)
- Baseline IOPS: 3,000 IOPS included for free
- Baseline Throughput: 125 MB/s included for free
If an application needs higher throughput or IOPS, you provision them independently without buying empty disk space:
- Additional IOPS: $0.005/IOPS-month (up to 16,000 IOPS total)
- Additional Throughput: $0.040/MB/s-month (up to 1,000 MB/s total)
In our storage section, you can check how these rates hold across global regions.
Cost comparison: gp2 vs gp3
The table below breaks down monthly spend in us-east-1 across common volume sizes.
| Volume Size | gp2 Cost & Specs | gp3 Baseline Cost & Specs | gp3 Matched Throughput Cost & Specs | Net Savings |
|---|---|---|---|---|
| 100 GB | $10.00 300 baseline IOPS (3k burst) 128 MB/s burst |
$8.00 3,000 sustained IOPS 125 MB/s sustained |
$13.00 (+125 MB/s) 3,000 sustained IOPS 250 MB/s sustained |
20% cheaper (10x baseline IOPS) |
| 500 GB | $50.00 1,500 baseline IOPS (3k burst) 250 MB/s sustained |
$40.00 3,000 sustained IOPS 125 MB/s sustained |
$45.00 (+125 MB/s) 3,000 sustained IOPS 250 MB/s sustained |
10% to 20% cheaper (2x baseline IOPS) |
| 2,000 GB (2 TB) | $200.00 6,000 baseline IOPS 250 MB/s sustained |
$160.00 3,000 sustained IOPS 125 MB/s sustained |
$180.00 (+3k IOPS, +125 MB/s) 6,000 sustained IOPS 250 MB/s sustained |
10% to 20% cheaper (identical performance) |
For small-to-medium volumes (under 1 TB), gp3 baseline is strictly superior: it cuts storage costs by 20% while giving small root disks 10x the sustained IOPS of gp2 without relying on burst credits.
For large volumes (over 1 TB) where gp2 already had high baseline IOPS and throughput, provisioning matching IOPS and throughput on gp3 still leaves you 10% ahead on total cost.
The io2 alternative: when do you actually need provisioned IOPS?
Before gp3, workloads needing consistent high IOPS had to choose between over-provisioning huge gp2 drives or buying Provisioned IOPS SSDs (io2).
io2 charges $0.125/GB-month for storage, plus tiered IOPS pricing:
- First 32,000 IOPS: $0.065/IOPS-month
- 32,001 to 64,000 IOPS: $0.0455/IOPS-month
- Above 64,000 IOPS: $0.03185/IOPS-month
Consider a 500 GB database volume requiring 16,000 IOPS:
-
On io2:
Storage: 500 GB × $0.125 = $62.50
IOPS: 16,000 × $0.065 = $1,040.00
Total: $1,102.50/month -
On gp3:
Storage: 500 GB × $0.080 = $40.00
IOPS: (16,000 − 3,000 free) × $0.005 = $65.00
Max throughput (1,000 MB/s): (1,000 − 125 free) × $0.040 = $35.00
Total: $140.00/month
gp3 delivers 16,000 IOPS and 1,000 MB/s for $140/month—an 87% reduction compared to io2.
Where is io2 still justified?
- Sub-millisecond latency SLAs: io2 provides single-digit millisecond latency with tighter variance guarantees than gp3.
- Durability requirements: io2 is engineered for 99.999% (five 9s) annual durability (a 0.001% annual failure rate), compared to gp2/gp3’s 99.8% to 99.9% durability (0.1% to 0.2% annual failure rate).
- Extreme scale: io2 scales up to 256,000 IOPS and 4,000 MB/s throughput on supported Nitro instances, far beyond gp3’s 16,000 IOPS and 1,000 MB/s limits.
For typical web servers, caching layers, container nodes, and mid-sized databases, gp3 makes io1 and io2 economically obsolete.
Why didn’t AWS migrate everyone automatically?
If gp3 is cheaper and better, why didn’t AWS automatically convert all gp2 volumes to gp3?
Three factors explain why the decision was left to customers:
1. Infrastructure as Code drift and API immutability
Modifying volume types at the infrastructure layer without customer intervention breaks declarative tooling. If AWS updated a volume from gp2 to gp3 under the hood, subsequent runs of Terraform, AWS CloudFormation, Pulumi, or the AWS CDK would detect configuration drift and attempt to revert the volume back to gp2.
2. Throughput differences on volumes over 334 GB
gp2 automatically scales throughput up to 250 MB/s for volumes over 334 GB. gp3 includes 125 MB/s baseline throughput by default. If AWS had blindly converted a 1 TB gp2 volume to gp3 baseline, that volume would experience a 50% drop in throughput (250 MB/s down to 125 MB/s).
To match the previous throughput, AWS would have had to provision an extra 125 MB/s ($5/month). AWS cannot unilaterally add line-item charges or alter performance characteristics on customer accounts.
3. Financial inertia
EBS represents a massive, recurring revenue stream. A mandatory, automatic migration to gp3 would have reduced AWS’s global EBS storage revenue by 20% overnight. By leaving migration manual, AWS rewards proactive engineering teams while continuing to collect full gp2 pricing on legacy deployments.
How to migrate: zero downtime with Elastic Volumes
EBS Elastic Volumes allows online volume modification with zero downtime. The drive remains attached and continues serving read/write operations while the underlying storage infrastructure transitions.
Migrating via the AWS CLI
To migrate a volume, call modify-volume:
aws ec2 modify-volume \
--volume-id vol-0123456789abcdef0 \
--volume-type gp3
For volumes larger than 334 GB where you want to maintain 250 MB/s throughput:
aws ec2 modify-volume \
--volume-id vol-0123456789abcdef0 \
--volume-type gp3 \
--throughput 250
Tracking migration progress
Once initiated, check the volume modification state:
aws ec2 describe-volumes-modifications \
--volume-ids vol-0123456789abcdef0
The volume transitions through three states:
modifying: The configuration request is being processed.optimizing: The performance characteristics of gp3 take effect immediately, while background data migration proceeds.completed: Fully migrated.
[!NOTE] AWS enforces a 6-hour cooldown period per volume after modifying size, IOPS, throughput, or volume type. Ensure your target settings are accurate before issuing the API call.
Finding unmigrated gp2 volumes
Use the AWS CLI to identify all active gp2 volumes across a region:
aws ec2 describe-volumes \
--filters Name=volume-type,Values=gp2 \
--query "Volumes[*].{ID:VolumeId,Size:Size,State:State,Instance:Attachments[0].InstanceId}" \
--output table
Summary
Unmigrated gp2 volumes represent pure waste in cloud budgets. gp3 delivers a 20% base storage discount, 3,000 guaranteed baseline IOPS, and decoupled performance scaling with zero migration downtime.
Review existing launch templates, Terraform modules, and root volume defaults. Every new gp2 allocation is an unforced error.