gp3 vs io2 — How to Choose an EBS Volume Type
Choosing an EBS volume type has narrowed to two questions: “is gp3 enough?” and “what actually justifies io2?” This post lays out working answers to both. The conclusion up front: gp3 is the right answer for most workloads, and io2 is chosen only when its requirements are explicit. The gap between spec sheets and measured storage performance (fsync, queue depth) is covered in Why Your Server Is Slow #3; here we focus on the AWS-side decision. Prices are for us-east-1.
gp2’s legacy — why so much gp2 is still around #
gp2 coupled performance to size: 3 IOPS per GB, so getting performance meant inflating capacity, and small volumes lived off burst credits that dropped performance in a step when they ran dry. Most “it was fine for days and suddenly got slow” EBS stories are that credit exhaustion.
gp3 severed the coupling. But volumes created in the gp2 era — and the templates and AMIs from that era — keep producing gp2 today, so plenty of accounts still carry it. gp3 is about 20% cheaper per GB and conversion is zero-downtime, which makes remaining gp2 effectively a cleanup item (see the standing checklist).
gp3 — independent provisioning and raised ceilings #
The gp3 model in three lines:
- You buy storage (about $0.08/GB-month) and performance separately.
- Every volume includes 3,000 IOPS and 125MiB/s regardless of size. There are no burst credits.
- Need more? Add IOPS (above 3,000, about $0.005/IOPS-month) and throughput (above 125MiB/s, about $0.04 per MB/s-month).
The ceilings have been raised too: up to 80,000 IOPS and 2,000MB/s per volume (it was 16,000 IOPS and 1,000MB/s for a long time, and older articles still quote the old limits). That increase moved the “we need io2 because of gp3’s ceiling” threshold far higher — most database-class workloads now fit inside gp3.
One caution: separate from the volume ceiling, there is an instance-side EBS bandwidth and IOPS limit. Provisioning 80,000 IOPS on a small instance gets clipped by the instance’s limit. Check the instance type’s EBS-optimized specs before scaling the volume.
io2 Block Express — a premium with explicit conditions #
Current io2 runs on the Block Express architecture, and it’s the choice under these conditions:
- Very high IOPS: up to 256,000 IOPS and 4,000MB/s per volume — the territory for workloads that measurably exceed gp3’s 80,000 ceiling.
- Consistent sub-millisecond latency: with Nitro instances, io2 delivers stable sub-millisecond I/O latency. That’s for transactional databases sensitive to latency spikes.
- Durability requirements: io2’s 99.999% durability is orders of magnitude above gp3’s (99.8–99.9%). On single-volume setups where losing the volume is an incident, that difference is real.
- IOPS density: up to 1,000 IOPS per GB, so small volumes needing high IOPS have a band where io2 wins.
Pricing is storage (about $0.125/GB-month) plus provisioned IOPS, with tiered IOPS rates (about $0.065 per IOPS up to 32,000, cheaper above). At equal performance it costs several times gp3, so “io2, just in case” is waste.
The decision — measure first #
Type selection starts with measurement, not spec comparison.
- Measure current consumption — CloudWatch volume metrics (
VolumeReadOps+VolumeWriteOpsconverted to per-second,VolumeThroughputPercentage, andBurstBalanceon gp2) give peak IOPS and throughput. On the OS side,iostat -x’s IOPS,aqu-sz, andawaitshow whether the disk is actually the bottleneck — reading those is covered in Why Your Server Is Slow #3. - Peak within 3,000 IOPS and 125MiB/s? Base gp3 and done. Most web/API servers and small databases live here.
- Peak above that? Add exactly the IOPS and throughput you need on gp3. Up to 80,000 IOPS and 2,000MB/s, gp3 is almost always cheaper than io2.
- Move to io2 when measured demand exceeds gp3’s ceiling, or when there’s an explicit requirement for sub-millisecond consistency, 99.999% durability, or per-GB IOPS density.
- Throughput-heavy sequential workloads still have the HDD tiers (st1), but with gp3’s throughput pricing as low as it is, standardizing on gp3 is often operationally simpler.
Conversion in practice — zero downtime via Elastic Volumes #
Type, size, and performance changes apply through Elastic Volumes without stopping the instance. aws ec2 modify-volume handles gp2 → gp3 conversion and IOPS increases online, with performance transitioning while the volume is in the optimizing state. Two cautions: a volume can be modified only once every 6 hours, and size only grows (shrinking means migrating to a new volume).
For bulk gp2 → gp3 conversion, just check for large volumes (over 1TB) whose size-proportional gp2 IOPS exceeded gp3’s base 3,000. For those, add IOPS to match their previous performance.
Summary #
- The default is gp3: storage and performance bought separately, no burst credits, 3,000 IOPS and 125MiB/s included.
- gp3’s ceilings were raised to 80,000 IOPS and 2,000MB/s. Material that picks io2 based on the old 16,000 limit is out of date.
- io2 Block Express is for explicit needs: up to 256,000 IOPS, sub-millisecond consistency, 99.999% durability, per-GB IOPS density.
- Choose from measurements (CloudWatch volume metrics, iostat), not spec sheets — and check the instance-side EBS limits along with the volume’s.
- Remaining gp2 converts to gp3 with zero downtime, so there’s no reason to postpone the ~20% saving.