Block vs File vs Object Storage
Three Ways to Say “Store This”
Say you have a gigabyte of data — a database, a folder of documents, a video. Before you can store it in the cloud, you have to answer a question most people never notice they're answering: which shape of storage do you want it in? There are three, and they are not interchangeable. The wrong one doesn't just cost more — it makes some of the things you want to do impossible.
The three shapes form a ladder, each rung built on the one below it:
- Block — the bottom rung, closest to a physical disk: a raw array of fixed-size blocks you address by number. No names, no files — you build structure on top.
- File — the middle rung: a tree of names and directories with the familiar open / read / write / seek, that many machines can mount and share.
- Object — the top rung: a flat key → an immutable blob, reached over HTTP, that scales to trillions of items and costs the least per gigabyte.
Climbing the ladder trades one thing for another, every rung: up buys you scale, sharing, and a lower price; down buys you latency, in-place editing, and control. (This is the layer above the disk physics from The Memory Hierarchy: Disk, RAM, CPU Cache and Sequential vs Random Access — those decide how fast a byte moves; this decides the shape you access it through.) Let's climb it from the bottom, on a real machine.

Block: a Raw Array of Numbered Blocks
The bottom rung is what a disk actually is to the operating system: a long, flat array of fixed-size blocks — 512 bytes or, today, 4 KB each — with no names and no structure. You don't ask for "the file cat.jpg"; you ask for "block number 91,204." Let's make one for real (a loopback device stands in for a cloud volume):
$ blockdev --getsize64 /dev/loop → 67108864 bytes (67 MB of addressable space)
$ blockdev --getbsz /dev/loop → 4096 bytes per block (you address by BLOCK NUMBER, not a name)
$ od -An -c /dev/loop | head -1 → \0 \0 \0 … (raw block 0 — no files, no names, just bytes)
That's the whole abstraction: addressable bytes, in numbered chunks, and nothing else. There is no concept of a file here. To get files, you (or your operating system) build a filesystem on top — or a database writes its pages straight to the raw blocks, which is exactly why databases love block storage: total control over the layout, and the lowest latency of the three, because it's a device attached directly to one machine.
And that's the catch built into the shape: a block volume is single-attach — it belongs to one host at a time, like a physical drive bolted into one server. You can't hand the same volume to five hundred machines. In the cloud this rung is AWS EBS (GCP Persistent Disk, Azure Managed Disk) — the thing you attach to one VM to hold its boot disk and its database files.
File: Names, a Tree, and Sharing
Put a filesystem on those raw blocks and you climb to the middle rung — the one you already know from your laptop. Now there are names, directories, and the whole POSIX vocabulary: open, read, write, seek, permissions, locks. Watch a block device become a file abstraction:
$ mkfs.ext4 /dev/loop && mount /mnt/v → now a TREE of names with POSIX read/write
$ echo "hello earth" > /mnt/v/note.txt → cat note.txt: hello earth
$ printf PLANET | dd of=note.txt bs=1 seek=6 conv=notrunc (write 6 bytes IN PLACE at offset 6)
$ cat note.txt → hello PLANET ← 6 bytes changed, size still 12 B
Two things there matter for the rest of the lesson. First, in-place editing: I changed six bytes in the middle of the file without rewriting the rest — seek to the offset, write, done. Second, and this is the whole reason file storage exists as a separate thing: a filesystem can be exported over a network protocol (NFS, SMB) so that many machines mount the same tree at once and read and write it concurrently. Block storage can't do that; a filesystem is built for it.
In the cloud this rung is AWS EFS (Amazon FSx, GCP Filestore, Azure Files): a managed, shared POSIX filesystem you mount on as many servers as you like. It's the answer when a fleet of app servers needs to see the same files — shared uploads, a content directory, an ML dataset mounted read-only by a hundred training nodes.
Object: a Flat Key → an Immutable Blob
The top rung throws away the tree entirely. Object storage is a flat namespace: you PUT a blob under a key and later GET it by that key — over HTTP, not a mount. Each object carries its data plus rich custom metadata, and there is no filesystem underneath that you can see. Here it is for real (MinIO speaks the S3 API):
$ PUT media/2024/07/cat.jpg → size=10,485,760 B type=image/jpeg metadata={album, camera}
$ GET over HTTP → http://…/media/2024/07/cat.jpg (fetched by URL, NOT mounted)
$ LIST → key = '2024/07/cat.jpg' ← ONE flat string; the '/' is just a char
Notice the key. It looks like a path — 2024/07/cat.jpg — but there are no folders. It is one flat string; the / is an ordinary character, and the tidy "folder" view in the S3 console is a cosmetic illusion the UI paints by splitting on slashes. There are no directories to create, no rename (that's a copy-then-delete), no locks.
And the defining constraint — the one that decides half your architecture — is that objects are immutable. There is no "write byte 500." To change anything, you replace the whole object with a new PUT:
$ change 1 byte in the middle → there is no such API. To edit, re-PUT the WHOLE object:
re-uploaded all 10,485,760 B to change 1 byte. (a file would have written 1 byte in place.)
$ update-byte-range API? → False (objects are IMMUTABLE)
You give up in-place editing and low latency; in return you get something the rungs below cannot touch — effectively infinite scale (trillions of keys, no volume ceiling), the cheapest price per gigabyte, eleven nines of durability, and an address that is already a URL. This rung is AWS S3 (GCP Cloud Storage, Azure Blob), and it is where the internet keeps its photos, videos, backups, logs, and data lakes.
What’s Cheap, Possible, or Forbidden
Here's the idea worth carrying out of this whole lesson, and it's bigger than three definitions: the abstraction you pick decides, before you write a line of code, what operations are cheap, which are expensive, and which are simply impossible. The disk underneath barely matters; the shape is everything.
You already saw the sharpest example: editing a few bytes is 6 bytes written in place on block and file, but a whole-object re-upload on object storage — 10 MB to change one, because objects are immutable. That single fact rules object storage out for anything that mutates in place, and rules it in for anything write-once. Below, throw operations at all three and watch each answer — cheap, costly, or impossible. Try to store a hundred billion items on a block volume; try to run a database on object storage; try to share a block volume with 500 servers. The failures are the lesson.

Three Prices, and How to Choose
Three shapes, three price tags — and the ranking is not the one people assume. Per gigabyte-month, object is the cheapest (0.08 on EBS), and file is the most expensive ($0.30 on EFS) — because with file storage you're paying for a whole managed shared filesystem, not just space. (The headline price hides fine print: object adds per-request fees, and block adds provisioned IOPS — but the per-GB order holds.)
So how do you actually choose? Two rules cover almost every case:
- Pick the lowest rung the workload genuinely needs. Each step up trades away latency and in-place control for scale and sharing you may not need — and "cheapest per gigabyte" is a trap if the shape can't do the job.
- Or pick by the one operation you need to be cheap — because the abstraction decides that.
In practice that lands as: block for a machine's boot disk and its database data files — one owner, low latency, a real filesystem. File when a fleet of servers must share the same tree and expect POSIX. Object for everything write-once-read-many at scale — backups, user uploads, images and video, static website assets, logs, data lakes — especially anything you'll serve straight over HTTP behind a CDN.

What to Remember
- ⭐ Three abstractions, one ladder. Block = raw numbered blocks, single-attach, lowest latency (EBS). File = a shared POSIX tree, mounted by many hosts (EFS). Object = a flat key → an immutable blob over HTTP, infinite scale, cheapest (S3). Each rung is built on the one below.
- ⭐⭐ The abstraction decides what's cheap, possible, or forbidden — before any code. Editing a few bytes is in place on block/file but a whole-object re-upload on object; a block volume can't be shared with 500 hosts; a database can't live on object storage.
- Object storage is not a filesystem over HTTP. Flat keys (the
/is just a character; folders are a console illusion), immutable objects (re-PUT to change anything), rich metadata, no seek/rename/lock. - Cheapest per GB isn't always right. Object is cheapest, file the priciest, block in between — but you pick the lowest rung the workload needs, or the one that makes your key operation cheap.
- The map: boot volumes & database files → block/EBS; a shared filesystem for many servers → file/EFS; backups, media, static assets, data lakes → object/S3.
Object storage is the one that runs the modern internet at scale — which raises the obvious question: how do you actually build a thing that stores trillions of immutable blobs, cheaply, with eleven nines of durability, addressed by a flat key? That's the next lesson — Design an S3: Blob Storage as a System — where you take this abstraction apart and assemble the metadata plane and the data plane that make it work.