Skip to content
AWS aws ec2 6 min read

EBS Volumes & Volume Types

Most EC2 instances need a disk that survives reboots and lives independently of the instance itself. That disk is an EBS volume. EBS (Elastic Block Store) is network-attached, durable block storage that you attach to an EC2 instance like a virtual hard drive. Because it lives on its own and is replicated automatically within a data center, your data stays safe even if you stop, start, or replace the instance.

What EBS is and why it matters

Block storage means the disk hands raw blocks to the operating system, and the OS puts a file system (like ext4 or XFS) on top. To Linux or Windows, an EBS volume looks and behaves exactly like a locally attached drive. The difference is that it is not physically inside the server. It lives on the network and connects to your instance over a high-speed AWS internal link.

That network attachment gives you two big wins. First, durability: AWS keeps multiple copies of your data inside one Availability Zone (an AZ, which is an isolated data center within a region), so a single disk failure does not lose your data. Second, persistence: when you stop or terminate an instance, the EBS volume can keep existing on its own, and you can re-attach it to a different instance later.

Key gotcha: An EBS volume is locked to a single Availability Zone. A volume created in us-east-1a can only attach to instances in us-east-1a. To move data to another AZ, you take a snapshot (a backup stored in S3) and create a new volume from it in the target AZ. See the snapshots page for how.

When to use EBS: any time you need persistent storage that outlives the instance, such as boot volumes, databases, or application data. When NOT to use it: for cheap, scratch data that you can lose on reboot, where the free local instance store is faster, or for shared file access across many instances, where EFS (Elastic File System) or FSx fit better.

Volume types — when to use which

EBS offers several volume types tuned for different price and performance needs. The two main families are SSD (solid-state, good for random reads and writes and low latency) and HDD (spinning disks, good for cheap, large, sequential throughput).

TypeFamilyBest forMax IOPSMax throughputNotes
gp3SSDDefault choice for most workloads, boot volumes, dev/test, web apps16,0001,000 MB/sIOPS and throughput priced separately from size
gp2SSDLegacy general-purpose; superseded by gp316,000250 MB/sIOPS tied to size; usually worth migrating off
io2 Block ExpressSSDMission-critical databases needing high, guaranteed IOPS256,0004,000 MB/sHighest durability and performance, highest cost
io1SSDOlder provisioned-IOPS workloads64,0001,000 MB/sLargely replaced by io2
st1HDDBig sequential workloads: log processing, data warehouses, streaming500500 MB/sThroughput-optimized, cannot be a boot volume
sc1HDDCold, rarely accessed data where cost is everything250250 MB/sCheapest per GB, cannot be a boot volume

IOPS stands for input/output operations per second (how many small reads/writes the disk handles). Throughput is how many megabytes per second it moves for large sequential transfers.

Migrate gp2 to gp3. gp3 is roughly 20% cheaper per GB than gp2, and it lets you provision IOPS and throughput independently of volume size. With gp2, you had to grow the disk just to get more speed. Most gp2 volumes should be moved to gp3. You can change the type live with no downtime using modify-volume.

Creating and attaching a volume

A new volume must be created in the same AZ as the instance you plan to attach it to.

Console steps

  1. Open the EC2 console and choose Volumes under Elastic Block Store in the left menu.
  2. Click Create volume.
  3. Set Volume type to gp3, Size to the GiB you need (for example 100), and pick the Availability Zone that matches your instance (for example us-east-1a).
  4. Optionally raise IOPS (default 3,000) and Throughput (default 125 MB/s).
  5. Add a Name tag, then click Create volume.
  6. Select the new volume, choose Actions -> Attach volume, pick your instance, and confirm the device name (for example /dev/sdf).

CLI equivalent

Create the volume:

aws ec2 create-volume \
  --availability-zone us-east-1a \
  --volume-type gp3 \
  --size 100 \
  --iops 3000 \
  --throughput 125 \
  --tag-specifications 'ResourceType=volume,Tags=[{Key=Name,Value=app-data}]'

Output:

{
    "VolumeId": "vol-0a1b2c3d4e5f67890",
    "AvailabilityZone": "us-east-1a",
    "VolumeType": "gp3",
    "Size": 100,
    "Iops": 3000,
    "Throughput": 125,
    "State": "creating",
    "Encrypted": true
}

Attach it to a running instance:

aws ec2 attach-volume \
  --volume-id vol-0a1b2c3d4e5f67890 \
  --instance-id i-0a1b2c3d4e5f \
  --device /dev/sdf

Output:

{
    "VolumeId": "vol-0a1b2c3d4e5f67890",
    "InstanceId": "i-0a1b2c3d4e5f",
    "Device": "/dev/sdf",
    "State": "attaching"
}

After attaching, the OS still needs a file system. On the instance, format and mount it once:

sudo mkfs -t xfs /dev/xvdf
sudo mkdir /data
sudo mount /dev/xvdf /data

AWS often presents /dev/sdf to the OS as /dev/xvdf (or /dev/nvme1n1 on Nitro instances). Run lsblk to see the real device name before formatting.

Migrating gp2 to gp3 with no downtime

You do not need to detach or stop the instance. A single modify-volume call switches the type while the volume stays attached and online.

aws ec2 modify-volume \
  --volume-id vol-0a1b2c3d4e5f67890 \
  --volume-type gp3 \
  --iops 3000 \
  --throughput 125

Output:

{
    "VolumeModification": {
        "VolumeId": "vol-0a1b2c3d4e5f67890",
        "TargetVolumeType": "gp3",
        "ModificationState": "modifying",
        "Progress": 0
    }
}

In the console, the same change is Actions -> Modify volume on the selected volume.

Defining an EBS volume in infrastructure as code

When you launch instances with CloudFormation, attach storage in the same template so the disk is created and wired up automatically.

Resources:
  AppVolume:
    Type: AWS::EC2::Volume
    Properties:
      AvailabilityZone: us-east-1a
      VolumeType: gp3
      Size: 100
      Iops: 3000
      Throughput: 125
      Encrypted: true
      Tags:
        - Key: Name
          Value: app-data

  VolumeAttachment:
    Type: AWS::EC2::VolumeAttachment
    Properties:
      InstanceId: i-0a1b2c3d4e5f
      VolumeId: !Ref AppVolume
      Device: /dev/sdf

Cost note

gp3 storage is about $0.08 per GiB-month in us-east-1, so a 100 GiB volume costs roughly $8 per month. You get 3,000 IOPS and 125 MB/s free at that tier; extra IOPS and throughput are billed separately but cheaply. Crucially, a volume keeps billing even while the instance is stopped, because the data is still stored. Delete volumes you no longer need, and watch for orphaned volumes left behind when instances are terminated.

Best practices

  • Use gp3 as your default volume type, and migrate existing gp2 volumes to cut cost and tune performance independently.
  • Enable encryption on every volume; it is free, and you can set it as an account default so it is never forgotten.
  • Set DeleteOnTermination correctly: true for throwaway boot volumes, false for data you must keep.
  • Tag volumes with their owner, environment, and purpose so you can find and clean up orphans later.
  • Take regular snapshots for backups and for moving data across Availability Zones.
  • Right-size IOPS and throughput from real CloudWatch metrics rather than over-provisioning by guesswork.
  • Run lsblk before formatting so you never overwrite the wrong device.
Last updated June 15, 2026
Was this helpful?