plainstackBook a free call
← All guides

Storage9 min read

gp2 vs gp3: which SSD to use, and what it costs you

EBS is billed on what you provisioned, not what you use — which explains almost the entire bill.

By Plainstack/

EBS is the quietest expensive thing in most AWS accounts. It doesn't appear as its own line in Cost Explorer — it's folded into EC2 — Other, alongside NAT Gateway and inter-AZ transfer — so it grows for years without anyone attributing the growth to it.

It's also the easiest place to find savings, because almost all of it is mechanical. No architecture decisions, no downtime, no risk to data.

The rule that explains most of the bill

You are billed for the storage you provisioned, not the storage you use.

A 500 GB volume with 40 GB of data on it costs exactly the same as a 500 GB volume that's full. Nothing in the EC2 console nudges you about this, and no alarm fires. It's the single most important thing to understand about EBS pricing, and it's why the fixes below are mostly about provisioning rather than about data.

A 500 GB VOLUME WITH 80 GB ON IT80 GB420 GB of empty spaceBILLED AT THE SAME RATEYOU PAY FOR THISEBS bills on provisioned size. Volumes can grow but cannot shrink — so provision smalland let autoscaling take it up, rather than sizing for three years out on day one.
Empty space on a provisioned volume is billed at exactly the same rate as the data next to it.

What gp2 and gp3 actually are

Both are general-purpose SSD volume types — the default disk you attach to an EC2 instance. gp2 is the older generation, gp3 the newer one. Everything below is about the difference between them and what it costs you.

There are four other types you'll see, and they matter less than people think: io1 and io2 are provisioned-IOPS SSD for genuinely latency-critical databases, and cost multiples of gp3. st1 and sc1 are spinning disk, for big sequential throughput workloads like log processing — cheap per gigabyte and hopeless at random access. If you are not certain you need one of those four, you want gp3.

gp3 is cheaper than gp2, and usually faster

If you still have gp2 volumes, this is close to free money.

gp2 ties performance to size. You get 3 IOPS per provisioned gigabyte, which means the only way to buy more performance is to buy more storage you don't need. A team that needed 6,000 IOPS had to provision 2 TB to get it, regardless of how much data they actually had.

gp3 decouples them. Performance stops being a function of size. Every gp3 volume includes a baseline of 3,000 IOPS and 125 MB/s of throughput regardless of size, and you can provision more of either independently. It's also meaningfully cheaper per gigabyte than gp2 — roughly 20% at time of writing, though you should check current pricing for your region.

So gp3 is usually cheaper and better at the same time, which is rare enough to be worth acting on.

The migration is online. You modify the volume type in place. No snapshot, no detach, no downtime, no instance restart. It's an aws ec2 modify-volume call or a couple of clicks, and it can be scripted across an account in an afternoon.

The two cases where you should check first

Not quite every gp2 volume should move blindly.

Large gp2 volumes. Because gp2 grants 3 IOPS per gigabyte, a volume above roughly 1 TB has a baseline above gp3's included 3,000 IOPS. A 4 TB gp2 volume gets around 12,000 baseline IOPS. Move that to gp3 without provisioning additional IOPS and you'll take a performance regression. Check the baseline you're currently getting, and provision gp3 IOPS to match where it matters — it's usually still cheaper, but do the arithmetic rather than assuming.

Small gp2 volumes that rely on burst credits. Volumes under 1 TB use a burst-credit mechanism to exceed their baseline. If a workload is quietly living on burst, compare against gp3's flat 3,000 IOPS before switching. In most cases gp3 is better, because 3,000 sustained beats a baseline of a few hundred with occasional bursts.

Volumes attached to nothing

Every EBS volume in the available state — meaning not attached to any instance — is billed at full price, forever, doing nothing.

They're created constantly. An instance terminates and its data volume isn't set to delete on termination. A migration leaves the old volume behind. Someone detaches a disk to investigate something and doesn't come back to it.

Filter the volumes list by state available and go through them. Some will be deliberate. Most won't be. Take a snapshot first if you're unsure — a snapshot costs a fraction of a live volume and can be restored.

While you're there, check the delete on termination flag on the volumes attached to your Auto Scaling groups. If it's off for data volumes, every scale-in event leaves an orphan behind, and the problem regenerates itself indefinitely.

Snapshots, which are more subtle than they look

Snapshots are incremental — each one stores only the blocks that changed since the previous snapshot — so a hundred snapshots of a mostly static volume don't cost a hundred times one snapshot.

The subtlety is that this makes deletion less predictable than people expect. Deleting a snapshot only frees the blocks that no other snapshot still references. Deleting an old snapshot from a long chain often frees far less than its nominal size. That's not a reason to keep them — it's a reason not to be surprised when deleting a few doesn't move the bill much.

What actually helps:

  • Delete snapshots whose source volume no longer exists, unless you have a documented reason to keep them. These are pure archaeology.
  • Use Data Lifecycle Manager to apply an actual retention policy, rather than relying on a script someone wrote once or on people remembering.
  • Watch AMIs. Deregistering an AMI does not delete the snapshots behind it. Old AMIs leave snapshot storage behind long after the image is gone, and nothing tells you.

Provisioned IOPS you aren't using

io1 and io2 volumes bill separately for provisioned IOPS, and that charge is substantial. They're the right choice for genuinely IO-intensive databases with strict latency requirements.

They're also frequently chosen out of caution — during a migration, when nobody was certain what the workload needed, and a safe over-provision seemed prudent. Then it stayed.

Check the actual consumed IOPS against what's provisioned. If you're using 2,000 of 20,000 provisioned, gp3 will do the job at a fraction of the price. gp3's included baseline covers a lot of workloads that were put on provisioned storage years ago.

Volumes that are simply too big

Since you're billed on provisioned size, an over-provisioned volume is a permanent overcharge. Compare filesystem usage against volume size across the fleet.

The awkward part: EBS volumes can grow but cannot shrink. Reducing a volume means creating a smaller one, copying the data across, and swapping them — real work with a maintenance window.

That makes this a lower priority than everything above it, and it makes the preventative version much more valuable: provision conservatively and grow when needed, because growing is easy and shrinking is not.

The rest of EC2 — Other

Once EBS is tidy, the same Cost Explorer bucket holds two other things worth checking:

  • NAT Gateway, which is frequently the largest item in there and has its own set of fixes. See why NAT Gateway bills get so high.
  • Inter-AZ data transfer, billed in both directions, usually generated by application tiers talking to databases in another Availability Zone.

Splitting EC2 — Other by usage type in Cost Explorer tells you which of the three you're actually dealing with, and takes about a minute.

The order worth working in

  1. Delete unattached volumes. Immediate, no risk with a snapshot taken first.
  2. Fix delete-on-termination so orphans stop being created.
  3. Migrate gp2 to gp3, checking baseline IOPS on volumes above about 1 TB.
  4. Sweep snapshots with no source volume, and put a lifecycle policy in place.
  5. Move unnecessary io1/io2 to gp3 after checking consumed versus provisioned IOPS.
  6. Right-size oversized volumes, last, because it's the only item here that needs a maintenance window.

Steps one through four are a single focused day for most accounts and need no downtime at all.

Not sure how much of your bill is sitting in EC2 — Other? The free teardown reads a Cost Explorer export and flags it when it's disproportionately large — which is the usual signal that some of the above applies to you.

Check your own account

Does this apply to you? Find out in two seconds.

Drop a Cost Explorer export into the free teardown. It reads your service mix and tells you which of these patterns show up in your bill — in your browser, with no upload and no email.