EBS (Elastic Block Store) and S3 (Simple Storage Service) get compared constantly, but they're not really competing for the same job. The confusion comes from both being labeled "storage" on the AWS console, which hides a much bigger difference underneath: one is a disk, the other is a filing system that happens to live on the internet.
What EBS actually is
EBS gives you block storage — raw, addressable blocks of data that an operating system can format with a filesystem (ext4, xfs, NTFS) and mount like a regular disk. It attaches to exactly one EC2 instance at a time (with the exception of io2 Block Express multi-attach, which is a narrow use case for clustered databases).
Continue reading
Drop your email to unlock the rest of this post — the full decision tree, durability numbers, and the cost breakdown.
What S3 actually is
S3 gives you object storage — whole files (objects) stored flat inside a bucket, addressed by a key (basically a path-like name), accessed over HTTP using a REST API. There's no filesystem to mount, no block-level access, and no OS-level dependency. You PUT an object, you GET it back. That's the core interaction model.
Because S3 isn't tied to a single EC2 instance, thousands of clients can read the same object at once. It's built for that kind of fan-out access pattern from day one.
The decision tree I actually use
Forget the marketing copy. In practice, the decision comes down to four questions, asked in this order:
1. Does an operating system need to boot from it or treat it as a disk?
If yes — root volumes, database data directories, anything that needs POSIX file semantics (random reads/writes at the byte level, file locking) — it has to be EBS. S3 cannot be mounted as a root volume and doesn't support partial in-place writes the way a block device does.
2. Does more than one compute resource need to read it concurrently?
If yes, lean S3. A standard EBS volume is single-attach; if ten Lambda functions or twenty EC2 instances all need to read the same file, EBS forces you into NFS-style workarounds (like EFS) or constant copying. S3 just serves it to all of them directly, with no attachment limit.
3. What does the durability requirement actually look like?
This is where people get the numbers wrong. EBS volumes replicate within a single Availability Zone — durable against a single disk failure, but not against an AZ-level event by default (you'd need snapshots to S3 for that). S3 Standard, by contrast, is engineered for 99.999999999% (11 nines) durability by replicating objects across a minimum of three Availability Zones automatically. If "what happens if this AZ goes down" is a question you need answered, S3 already has a better default answer.
4. What's the access pattern's relationship with the data over time?
EBS is priced and built for active, frequent, low-latency block I/O — the kind a running database needs every second. S3 is priced and built around storage classes that assume most objects get colder over time: Standard for active access, Standard-IA for infrequent access, Glacier for archival. If your data has a "hot now, rarely touched later" lifecycle, S3's storage class tiers (covered properly in the lifecycle policy post) do that cost optimization automatically. EBS has no equivalent tiering — you pay the same per-GB rate whether the volume is touched every second or never.
Latency: the number that actually matters
EBS volumes (especially io2/io1) deliver sub-millisecond latency because they're attached block devices on the same network fabric as the instance. S3 latency for a single object GET typically lands in the 10–20ms range for first-byte, because every request is a full HTTP round trip through S3's distributed system, not a local block read.
This is the one number that should immediately rule S3 out for transactional database storage and immediately rule EBS out for serving static assets to the public internet. A database doing thousands of small reads/writes per second cannot tolerate S3's latency profile. A static website serving images to browsers doesn't need EBS's latency profile, and would cost far more to run that way.
Cost shape, not just price
EBS bills you for provisioned capacity whether you use it or not — a 100GB gp3 volume costs the same whether it's 10% full or 100% full. S3 bills you only for what you actually store, plus request and transfer costs. For data with unpredictable or growing size (logs, backups, user uploads), that billing model alone often makes S3 the financially sane default, separate from any architectural reason.
The pattern I actually deploy
In nearly every production system I've built, the two end up working together rather than competing:
- EBS holds the database's data directory, mounted on the EC2 instance(s) actually running the database engine.
- S3 holds everything that needs to survive instance termination, be shared across instances, or scale beyond a single attachment — backups, uploaded user files, static assets, build artifacts.
The Flask image-upload app migrated from EFS to S3 is a direct example of this: the app logic and OS stayed on EBS-backed root volumes, while user-uploaded images moved to S3 with pre-signed URLs, removing the need for any shared block storage between instances entirely.
One thing to stop assuming
S3 is not "slower EBS" and EBS is not "faster S3." They solve different problems. The moment you're choosing between them for the same workload, one of the four questions above usually already answered it — you just haven't asked it explicitly yet.