EBS vs EFS: Block vs Shared File Storage
AWS gives you two very different storage primitives for compute, and picking the wrong one shows up as either a scaling wall or a bill you did not expect.
Search across all documentation pages
AWS gives you two very different storage primitives for compute, and picking the wrong one shows up as either a scaling wall or a bill you did not expect.
EBS (Elastic Block Store) is a virtual hard disk you attach to a single EC2 instance. EFS (Elastic File System) is a shared filesystem that many instances mount at the same time. This page builds the mental model for both, shows where the SDK's job ends and the operating system's begins, and gives you a rule for choosing.
Start with the physical analogy, because it holds up well.
An EBS volume is like an external SSD. You plug exactly one into one computer, the operating system sees a raw block device (/dev/xvdf), you put a filesystem on it (mkfs), and you mount it at a path. The disk is fast and private to that machine. It lives in one Availability Zone, and if the instance moves to another AZ the volume cannot follow without a snapshot.
An EFS file system is like a network drive the whole office shares. It already has a filesystem - you never format it. Any number of machines mount it over NFS at the same time, in any Availability Zone in the region, and they all see the same files instantly. Capacity is elastic: it grows as you write and shrinks as you delete, and you pay for what you store.
That difference - one private disk versus one shared filesystem - drives every other trade-off.
From the SDK, the two live in different clients. EBS is part of EC2, so you use @aws-sdk/client-ec2 (or boto3.client("ec2")). EFS has its own service, so you use @aws-sdk/client-efs (or boto3.client("efs")).
# --- Python (boto3) ---
import boto3
ec2 = boto3.client("ec2") # EBS lives inside EC2
efs = boto3.client("efs") # EFS is its own service// --- TypeScript (AWS SDK v3) ---
import { EC2Client } from "@aws-sdk/client-ec2"; // EBS lives inside EC2
import { EFSClient } from "@aws-sdk/client-efs"; // EFS is its own service
const ec2 = new EC2Client({});
const efs = new EFSClient({});The most important thing to understand is where the SDK stops.
Provisioning is an API call. Mounting is not. When you CreateVolume or CreateFileSystem, you have created storage in AWS, but no instance can use it yet. Making it usable is a two-step dance: the SDK connects the storage to the network, then the operating system on the instance mounts it.
For EBS, the SDK call is AttachVolume, which exposes the volume to a running instance as a block device. After that, a human or a boot script runs OS commands to format and mount it. Those commands are shell, not SDK.
# --- Python (boto3) ---
# SDK attaches the volume as a block device on the instance...
ec2.attach_volume(VolumeId="vol-0abc", InstanceId="i-0def", Device="/dev/sdf")// --- TypeScript (AWS SDK v3) ---
import { AttachVolumeCommand } from "@aws-sdk/client-ec2";
// SDK attaches the volume as a block device on the instance...
await ec2.send(new AttachVolumeCommand({ VolumeId: "vol-0abc", InstanceId: "i-0def", Device: "/dev/sdf" }));# ...then the OS on the instance formats and mounts it (NOT the SDK):
sudo mkfs -t xfs /dev/xvdf
sudo mkdir -p /data
sudo mount /dev/xvdf /dataFor EFS, the SDK creates the file system and a mount target in each Availability Zone's subnet (an ENI with an IP the NFS client connects to). The instance then mounts it over NFS, usually via the Amazon EFS mount helper.
# EFS is mounted over NFS on the instance (NOT the SDK):
sudo mount -t efs -o tls fs-0123456789abcdef0:/ /mnt/efsSo the SDK's role is provision, connect, and manage; the instance's role is mount. Keeping that boundary clear prevents a common confusion: there is no MountVolume or MountFileSystem API, because mounting is a Linux operation.
Networking also differs. An EBS volume has no security group of its own - access is implicit once attached. An EFS mount target sits in a subnet behind a security group, so the instance's SG must be allowed to reach the mount target's SG on the NFS port (2049).
Use this table as the decision core.
| Dimension | EBS (block) | EFS (shared file) |
|---|---|---|
| Attaches to | One instance (single-AZ) | Many instances, all AZs in region |
| You provide the filesystem? | Yes - you mkfs and mount | No - it is already a filesystem |
| SDK client | @aws-sdk/client-ec2 | @aws-sdk/client-efs |
| Capacity | Fixed at create, grown explicitly | Elastic - grows/shrinks automatically |
| Latency | Lowest (local block device) | Higher (network filesystem) |
| Typical use | Databases, boot volumes, low-latency disk | Shared content, CMS uploads, ML datasets, HPC |
| Billing | Per GB provisioned (plus IOPS/throughput) | Per GB stored (plus optional throughput) |
Reach for EBS when a single instance needs the fastest possible disk and no one else needs those bytes at the same time - a relational database's data directory, a boot volume, a build cache. You control size, IOPS, and throughput precisely, and you can snapshot it for backup or clone it into another AZ.
Reach for EFS when the same files must be visible to many consumers at once - a fleet of web servers serving user uploads, containers in an Auto Scaling group sharing state, a training cluster reading one dataset, or a lift-and-shift app that expects a POSIX mount. EFS removes the "which instance has the file?" problem entirely.
A frequent hybrid: boot and run the OS from EBS, and mount EFS for the shared data directory. They are not competitors so much as different layers.
One more application note: EBS is the substrate for a lot of higher-level features. Snapshots (point-in-time backups stored in S3), encryption at rest via KMS, and elastic volume modification (resize and retype without downtime) are all EBS concepts covered in the next pages. EFS's parallels are access points (per-application entry points with a POSIX identity) and lifecycle management (tiering cold files to cheaper storage). Same goal - manage the storage through the API - expressed in two different services.
mount. There is no mount API.EBS is a private virtual disk for one instance in one AZ; EFS is a shared filesystem many instances mount concurrently across a whole region.
EBS is part of EC2, so @aws-sdk/client-ec2 / boto3.client("ec2"). EFS has its own service, so @aws-sdk/client-efs / boto3.client("efs").
No. The SDK provisions and connects the storage (CreateVolume + AttachVolume, or CreateFileSystem + CreateMountTarget). Mounting is an OS command (mount) run on the instance.
Only with io1/io2 Multi-Attach and a cluster-aware filesystem, which is a niche case. For ordinary shared access use EFS, which is built for concurrent multi-instance mounts.
Not directly. Take a snapshot, then create a new volume from that snapshot in the destination AZ. Snapshots are the cross-AZ (and cross-region) transport for block data.
No. EFS is already a POSIX filesystem - you just mount it. You only run mkfs on EBS volumes, which start as raw block devices.
EBS, because it is a local block device with the lowest latency. EFS is a network filesystem, so it trades some latency for shared access and elastic capacity.
EBS bills per GB you provision (plus provisioned IOPS/throughput on some types), whether or not it is full. EFS bills per GB actually stored, plus optional throughput, and can tier cold data cheaper.
Yes, commonly. Run the OS and low-latency data on EBS, and mount EFS for the directory that must be shared across a fleet. They serve different layers.
EFS mount targets are network endpoints (ENIs) reached over NFS on port 2049, so they sit behind a security group. An EBS volume is attached directly to one instance and has no network endpoint of its own.
Stack versions: This page was written for boto3 1.43.x (Python 3.10+) and the AWS SDK for JavaScript v3 (Node.js 18+).
Reviewed by Chris St. John·Last updated Jul 23, 2026