Pushpjeet Cholkar

Blog

Amazon S3 vs EBS vs EFS: Which AWS Storage Should You Use?

October 8, 2026 · Pushpjeet Cholkar

Last updated:

Short answer: Use Amazon S3 for objects such as files, backups, images and data lakes that applications reach through an API. Use Amazon EBS as a low-latency disk attached to one EC2 instance, for boot volumes and databases. Use Amazon EFS when many Linux servers, containers or Lambda functions must share the same files over NFS.

S3 vs EBS vs EFS at a glance

Amazon S3 Amazon EBS Amazon EFS
Storage type Object Block (a virtual disk) File (NFS v4.0 / v4.1)
How you access it HTTPS API, SDK, CLI Attached to an EC2 instance as a device, then formatted and mounted Mounted as a shared folder by many clients
Scope Regional bucket; most classes store data across 3 or more AZs One Availability Zone Regional (multi-AZ) or One Zone
Who can use it at once Any number of clients One instance (io1/io2 Multi-Attach: up to 16 Nitro instances in one AZ) Many clients at once across AZs: EC2, ECS, EKS, Lambda, Fargate
Size Unlimited objects; up to 48.8 TiB per object gp3: 1 GiB to 64 TiB per volume Grows and shrinks automatically to petabyte scale
Performance headline Massive parallel throughput, millisecond first byte (Express One Zone: single-digit ms) gp3: 3,000 IOPS and 125 MiB/s baseline, up to 80,000 IOPS and 2,000 MiB/s; io2 Block Express up to 256,000 IOPS Elastic throughput scales with the workload; sub-millisecond latency on EFS Standard
Durability (designed for) 99.999999999% (11 nines) 99.8–99.9% (gp3, gp2, io1); 99.999% (io2) 99.999999999% (11 nines)
Windows support Yes, through the API Yes No (use FSx for Windows File Server)
You pay for Data stored per class, requests, retrieval for some classes, data transfer Provisioned size, plus extra IOPS/throughput where provisioned, plus snapshots Data stored per class, throughput (Elastic or Provisioned), IA/Archive access
Typical uses Static assets, uploads, backups, logs, data lakes, ML datasets Boot volumes, self-managed databases, single-server apps Shared web content, home directories, CI/CD build caches, containers needing shared state

Figures from AWS documentation, checked October 9, 2026. Limits change, so confirm them in the linked docs before you design around them.

What is Amazon S3?

Amazon S3 (Simple Storage Service) stores data as objects inside buckets. An object is the file plus its metadata, addressed by a key such as reports/2026/q3.csv. You don’t mount S3 like a disk in its native form. Applications read and write objects through the S3 API, an AWS SDK or the CLI.

Facts worth remembering:

Use S3 when the data is written once and read many times, is shared with many clients, or needs to sit cheaply for years: user uploads, static website assets, log archives, database backups, data lakes and training data for ML. If you want to go deeper on buckets, lifecycle rules, encryption and bucket policies, the AWS S3 course covers them in labs.

What is Amazon EBS?

Amazon EBS (Elastic Block Store) provides block storage volumes for EC2. Think of an EBS volume as a network-attached hard disk. After you attach it, the instance sees a raw block device. You put a file system on it (XFS, ext4 or NTFS), mount it, and use it like any local disk.

Facts worth remembering:

Use EBS when one server needs a fast, persistent disk: the root volume of every EC2 instance, a PostgreSQL or Oracle database you run yourself, or an application that expects a local disk.

Don’t confuse EBS with instance store. Some instance types include instance store volumes, which are physically attached temporary disks. Their data survives a reboot but not a stop, hibernation or termination. Use them only for caches and scratch data.

What is Amazon EFS?

Amazon EFS (Elastic File System) is a serverless, elastic file system that speaks NFS v4.0 and v4.1. Many clients mount the same file system at once and see the same directories, with strong consistency and file locking. You don’t provision capacity; it grows and shrinks as you add and remove files.

Facts worth remembering:

Use EFS when several Linux servers or containers need the same files: shared web content for a CMS, user home directories, build caches for CI/CD, or a shared model and asset folder for containers on ECS or EKS.

How do S3, EBS and EFS differ in practice?

Scope: Region or Availability Zone?

This is where most designs go wrong. S3 buckets are Regional and, in most storage classes, survive the loss of a whole Availability Zone. EFS Regional file systems are reachable from mount targets in every zone. EBS volumes are tied to one zone. If your Auto Scaling group launches an instance in us-east-1b, it cannot attach a volume that lives in us-east-1a.

Sharing: one writer or many?

S3 and EFS are built for many concurrent clients. EBS is built for one. Multi-Attach exists for clustered software that coordinates writes. It is not a shortcut to a shared drive.

Performance: latency or throughput?

EBS gives the lowest latency to a single instance because it behaves like a local disk. EFS adds network file system overhead but scales throughput across many clients. S3 has higher per-request latency than a disk, yet it can deliver very high aggregate throughput when many clients read large objects in parallel.

Durability and backup

S3 and EFS are designed for 11 nines and store data across zones (except the One Zone options). An EBS volume lives in one zone and is designed for 99.8–99.9% annual durability for most types (99.999% for io2). That is why snapshots matter: they protect you from both volume failure and your own mistakes.

How is each one priced?

This post doesn’t quote prices. They vary by Region and change over time. The pricing model is what affects architecture:

Practical tip: in Elastic throughput mode EFS meters each data I/O at a minimum of 32 KiB, so workloads with millions of tiny reads and writes can cost more than you expect. Test with real traffic before you commit.

Which one should you use? A decision guide

Your situation Pick Why
Website images, user uploads, static assets S3 Any number of clients, 11 nines durability, no servers to manage
Root volume for an EC2 instance EBS gp3 Boot volumes need a block device
PostgreSQL, MySQL or Oracle that you run on EC2 EBS gp3 or io2 Low latency, consistent IOPS for one database server
WordPress or Drupal on several Linux web servers EFS Every server sees the same uploads and plugins folder
Shared folder for Windows servers FSx for Windows File Server EFS does not support Windows clients
Backups, logs, compliance archives S3 with lifecycle rules to Glacier classes Cheapest long-term storage, lifecycle automation
ML training data read by many jobs S3 (add S3 Files if your tools need file paths) Scales out, data stays in one place
Shared state for ECS or EKS containers EFS Pods and tasks move between nodes and zones; the files follow
Clustered app that writes one disk from two nodes EBS io2 with Multi-Attach Only with cluster-aware software; otherwise redesign

To make the first questions concrete, here is a small Python rule-of-thumb picker. It is a teaching aid, not a sizing tool.

def pick_storage(access: str, shared: bool = False, client_os: str = "linux",
                 boot_or_db: bool = False) -> str:
    """Return a storage recommendation with a one-line reason.

    access     -- "object" (whole files over HTTP/API), "block" (a disk),
                  or "file" (a mounted folder with paths and locks)
    shared     -- True if several servers must read/write the same data
    client_os  -- "linux" or "windows"
    boot_or_db -- True for a root volume or a self-managed database on EC2
    """
    if access == "object":
        return "Amazon S3: object storage over an API, any number of clients"
    if boot_or_db or access == "block":
        if shared:
            return ("Amazon EBS io1/io2 with Multi-Attach (same AZ, Nitro, "
                    "cluster-aware file system) or rethink the design")
        return "Amazon EBS (gp3 to start): a low-latency disk for one instance"
    if access == "file":
        if client_os == "windows":
            return "Amazon FSx for Windows File Server: EFS does not support Windows"
        return "Amazon EFS: shared NFS file system across instances and AZs"
    raise ValueError("access must be 'object', 'block' or 'file'")


scenarios = [
    ("Static website images and user uploads", dict(access="object")),
    ("PostgreSQL you run yourself on EC2", dict(access="block", boot_or_db=True)),
    ("WordPress on 3 Linux web servers sharing wp-content",
     dict(access="file", shared=True)),
    ("Shared drive for Windows app servers", dict(access="file", shared=True, client_os="windows")),
    ("Clustered app writing one disk from 2 nodes",
     dict(access="block", shared=True)),
]
for name, kwargs in scenarios:
    print(f"{name}\n  -> {pick_storage(**kwargs)}")

Output (run with Python 3.13):

Static website images and user uploads
  -> Amazon S3: object storage over an API, any number of clients
PostgreSQL you run yourself on EC2
  -> Amazon EBS (gp3 to start): a low-latency disk for one instance
WordPress on 3 Linux web servers sharing wp-content
  -> Amazon EFS: shared NFS file system across instances and AZs
Shared drive for Windows app servers
  -> Amazon FSx for Windows File Server: EFS does not support Windows
Clustered app writing one disk from 2 nodes
  -> Amazon EBS io1/io2 with Multi-Attach (same AZ, Nitro, cluster-aware file system) or rethink the design

What about Amazon S3 Files and Mountpoint for S3?

Two newer options blur the old “S3 is not a file system” rule, so it helps to know where they fit.

Neither replaces EBS for a database, and neither is a reason to move a working EFS file system. They remove the need to copy S3 data into EFS just so a file-based tool can use it.

Hands-on: create one of each with the AWS CLI

This short lab makes the differences concrete. You will create an S3 bucket, a gp3 EBS volume and an EFS file system, use each from one EC2 instance, then delete everything.

Replace the placeholder IDs (i-1234567890abcdef0, sg-..., subnet-...) with your own.

Step 1: Create an S3 bucket and upload an object

Bucket names must be unique, so add your own suffix. In us-east-1 you don’t pass a location constraint.

aws s3api create-bucket --bucket pc-storage-demo-12345 --region us-east-1
echo "region,revenue" > report.csv
aws s3 cp report.csv s3://pc-storage-demo-12345/reports/report.csv
aws s3 ls s3://pc-storage-demo-12345/reports/

Expected output (illustrative):

{
    "Location": "/pc-storage-demo-12345"
}
upload: ./report.csv to s3://pc-storage-demo-12345/reports/report.csv
2026-10-09 10:15:02         15 report.csv

Notice there is no mounting and no file system. You put and get whole objects by key.

Step 2: Create, attach and mount an EBS gp3 volume

Create the volume in the same Availability Zone as your instance.

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

Expected output (illustrative, trimmed):

{
    "AvailabilityZone": "us-east-1a",
    "Encrypted": true,
    "Size": 20,
    "State": "creating",
    "VolumeId": "vol-1234567890abcdef0",
    "Iops": 3000,
    "VolumeType": "gp3",
    "MultiAttachEnabled": false,
    "Throughput": 125
}

When the volume state is available, attach it:

aws ec2 describe-volumes --volume-ids vol-1234567890abcdef0 --query "Volumes[0].State"
aws ec2 attach-volume --volume-id vol-1234567890abcdef0 \
  --instance-id i-1234567890abcdef0 --device /dev/sdf
"available"
{
    "AttachTime": "2026-10-09T10:20:31.000Z",
    "Device": "/dev/sdf",
    "InstanceId": "i-1234567890abcdef0",
    "State": "attaching",
    "VolumeId": "vol-1234567890abcdef0"
}

Now SSH to the instance. On Nitro-based instances the volume appears as an NVMe device, so /dev/sdf shows up as something like nvme1n1. Always confirm with lsblk before formatting.

lsblk
sudo file -s /dev/nvme1n1        # "data" means no file system yet
sudo mkfs -t xfs /dev/nvme1n1    # only on a NEW, empty volume: this erases data
sudo mkdir /data
sudo mount /dev/nvme1n1 /data
df -h /data

Expected output (illustrative):

NAME          MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
nvme0n1       259:0    0   8G  0 disk
├─nvme0n1p1   259:1    0   8G  0 part /
└─nvme0n1p128 259:2    0   1M  0 part
nvme1n1       259:3    0  20G  0 disk
/dev/nvme1n1: data
Filesystem      Size  Used Avail Use% Mounted on
/dev/nvme1n1     20G  175M   20G   1% /data

This is block storage: a raw disk that you format and own. Only this one instance can mount it. The mount does not survive a reboot unless you add it to /etc/fstab (use the UUID and the nofail option).

Step 3: Create and mount an EFS file system

Create the file system with the recommended General Purpose performance mode and Elastic throughput:

aws efs create-file-system \
  --performance-mode generalPurpose --throughput-mode elastic \
  --encrypted --tags Key=Name,Value=demo-efs
{
    "FileSystemId": "fs-0123456789abcdef0",
    "LifeCycleState": "creating",
    "NumberOfMountTargets": 0,
    "PerformanceMode": "generalPurpose",
    "Encrypted": true,
    "ThroughputMode": "elastic"
}

Allow NFS from the instance’s security group to the mount target’s security group, then create a mount target in the instance’s subnet. In production, create one mount target in each Availability Zone you use.

aws efs describe-file-systems --file-system-id fs-0123456789abcdef0 \
  --query "FileSystems[0].LifeCycleState"
aws ec2 authorize-security-group-ingress --group-id sg-0aaaaaaaaaaaaaaaa \
  --protocol tcp --port 2049 --source-group sg-0bbbbbbbbbbbbbbbb
aws efs create-mount-target --file-system-id fs-0123456789abcdef0 \
  --subnet-id subnet-0123456789abcdef0 --security-groups sg-0aaaaaaaaaaaaaaaa

Here sg-0aaaaaaaaaaaaaaaa is the mount target’s group and sg-0bbbbbbbbbbbbbbbb is the instance’s group.

"available"
{
    "MountTargetId": "fsmt-0123456789abcdef0",
    "FileSystemId": "fs-0123456789abcdef0",
    "SubnetId": "subnet-0123456789abcdef0",
    "LifeCycleState": "creating",
    "IpAddress": "10.0.1.25",
    "AvailabilityZoneName": "us-east-1a"
}

On the instance, install the EFS mount helper and mount with TLS so data is encrypted in transit:

sudo dnf install -y amazon-efs-utils
sudo mkdir -p /mnt/efs
sudo mount -t efs -o tls fs-0123456789abcdef0:/ /mnt/efs
df -h /mnt/efs
Filesystem      Size  Used Avail Use% Mounted on
127.0.0.1:/     8.0E     0  8.0E   0% /mnt/efs

The huge size is not a mistake. EFS has no fixed capacity, so it reports a very large number and bills only for what you store. Mount the same file system on a second instance and both see the same files.

Step 4: Clean up

# On the instance
sudo umount /data /mnt/efs

# From your workstation
aws ec2 detach-volume --volume-id vol-1234567890abcdef0
aws ec2 delete-volume --volume-id vol-1234567890abcdef0   # after it shows "available"
aws efs delete-mount-target --mount-target-id fsmt-0123456789abcdef0
aws efs delete-file-system --file-system-id fs-0123456789abcdef0   # after mount targets are gone
aws s3 rb s3://pc-storage-demo-12345 --force   # deletes all objects, then the bucket

If you repeat labs like this often, wrap the create and cleanup commands in a script with set -euo pipefail and checks between steps. The Bash Scripting: Zero to Pro tutorial shows the patterns.

Common mistakes with S3, EBS and EFS

  1. Expecting an EBS volume to follow an instance to another zone. It can’t. Snapshot it and create a new volume in the target zone, or use EFS or S3 for data that must be reachable from every zone.
  2. Using Multi-Attach as a shared drive. Mounting one XFS or ext4 volume read-write on two instances corrupts data. Multi-Attach needs a cluster-aware file system.
  3. Planning EFS for Windows servers. It isn’t supported. Use FSx for Windows File Server.
  4. Treating S3 as a POSIX file system. Mountpoint for S3 can’t modify existing files. If tools need real file semantics on S3 data, evaluate S3 Files.
  5. Paying for forgotten EBS volumes. EBS bills for provisioned size even when unattached. Volumes kept after termination (DeleteOnTermination set to false) keep incurring charges until you delete them.
  6. Assuming AWS backs up EBS for you. It doesn’t. Automate snapshots with AWS Backup or Data Lifecycle Manager and test a restore.
  7. Putting valuable data on instance store. It is erased on stop, hibernation and termination.

A real-world example: one web application, all three services

A common three-tier design on AWS uses each service for what it does best:

Choosing storage is a recurring theme in AWS Solutions Architect Associate exam scenarios. If you’re preparing for the exam, practice spotting the clue words: “shared”, “POSIX”, “single AZ”, “archive”, “boot volume”. The AWS Solutions Architect course drills these scenarios in labs.

Frequently asked questions

Is S3 faster than EBS?

For a single server reading and writing small blocks, no. EBS is a disk attached to the instance and is built for low-latency I/O. S3 is accessed over an API and shines at large objects and massive parallel throughput from many clients. Pick by access pattern, not by a single speed number.

Can I attach one EBS volume to multiple EC2 instances?

Only Provisioned IOPS io1 and io2 volumes with Multi-Attach, up to 16 Nitro-based instances in the same Availability Zone, and your software must coordinate writes with a cluster-aware file system. For ordinary shared files across servers, use Amazon EFS.

Can Amazon EFS be used with Windows?

No. AWS states that using Amazon EFS with Microsoft Windows-based EC2 instances is not supported. For shared SMB file storage for Windows, use Amazon FSx for Windows File Server.

Which is cheapest: S3, EBS or EFS?

It depends on the workload. S3 bills for data stored per storage class plus requests and transfer. EBS bills for the size you provision, even if the disk is empty. EFS bills for data stored per storage class plus throughput in Elastic mode. Model your own numbers in the AWS Pricing Calculator.

Is Amazon S3 Files the same as Amazon EFS?

No. S3 Files, generally available since April 2026, is built using Amazon EFS but gives file system access to data that stays in an S3 bucket. EFS is a standalone file system that holds its own data. Use S3 Files when the data already lives in S3 and file-based tools need to read and write it.

What happens to an EBS volume when I terminate the instance?

It depends on the DeleteOnTermination setting. If it is true, the volume is deleted with the instance. If it is false, the volume is kept and keeps incurring charges until you delete it. Instance store data, by contrast, does not survive a stop or termination.

Sources

All checked on October 9, 2026.


Train your team on this. If your team needs hands-on AWS training on storage, networking and architecture, see AWS training for teams and live batches. For an existing design you’d like reviewed, see AWS consulting.

More AWS guides and labs: AWS tutorials and guides.

Newsletter

Enjoyed this post?

Get new posts, AI/ML tutorials, AWS batch dates and Oracle tips by email. No spam, unsubscribe anytime.

I’m interested in

Double opt-in: you’ll get a confirmation email first. Privacy policy