Objects, Keys & Prefixes
Amazon S3 (Simple Storage Service, AWS’s object storage service) stores your data as objects inside buckets. The Console shows those objects sitting inside neat folders, which makes S3 feel like a regular file system. It is not. Under the hood, S3 is a flat key-value store with no real directories at all. Understanding what an object, a key, and a prefix actually are will save you from listing bugs, broken lifecycle rules, and accidentally slow designs.
What an object actually is
An S3 object is a single piece of stored data plus information about that data. Every object has three parts:
- Data (the body) — the bytes you uploaded: an image, a video, a JSON file, a backup, anything up to 5 TB.
- Key — the full, unique name of the object within the bucket (more on this below).
- Metadata — key-value pairs describing the object. Some is system metadata (like
Content-Type,Last-Modified, size, and storage class). Some is custom metadata you set yourself (headers prefixed withx-amz-meta-).
You always retrieve an object by its key. There is no way to “open a folder and look inside” at the storage layer, because folders do not exist there.
What a key is
The key is the complete name of an object inside a bucket. It is just a string, and it is unique within that bucket. A key can be up to 1,024 bytes of UTF-8 characters and may contain slashes (/), but the slashes carry no special meaning to S3 — they are ordinary characters in the name.
So this key:
invoices/2026/06/inv-1042.pdf
is not a file called inv-1042.pdf living three folders deep. It is a single object whose entire name happens to be invoices/2026/06/inv-1042.pdf. The bucket has no invoices folder and no 2026 folder. There is only one flat list of keys.
The bucket name plus the key form the object’s address. The S3 URI is
s3://my-bucket/invoices/2026/06/inv-1042.pdf. There is nothing between the bucket and the full key.
What a prefix is, and why folders are an illusion
A prefix is simply the leading part of a key up to a chosen delimiter — almost always the / character. When you ask the Console (or the CLI) to “list a folder,” what really happens is:
- S3 scans all keys in the bucket.
- It groups keys that share the same prefix up to the next
/. - The Console draws each unique prefix as a folder icon.
That is the entire trick. The “folder” invoices/2026/ is just every key that starts with the string invoices/2026/. Delete every object under it and the folder vanishes, because it was never a real thing — it was a visual summary of matching prefixes.
Listing with a delimiter
The CLI exposes this directly. The --delimiter / flag tells S3 to collapse everything after the first slash into a “common prefix.”
aws s3api list-objects-v2 \
--bucket my-app-data \
--prefix invoices/2026/ \
--delimiter /
Output:
{
"CommonPrefixes": [
{ "Prefix": "invoices/2026/05/" },
{ "Prefix": "invoices/2026/06/" }
]
}
Notice you got back prefixes, not folders. The friendlier aws s3 ls command does the same grouping for you and prints PRE lines for prefixes.
Creating a “folder” (and why you usually shouldn’t)
Because folders are not real, you rarely need to create one. Uploading an object with a key like reports/q2.csv instantly makes reports/ appear as a folder. You do not create the folder first.
The Console does let you make an empty folder. When you do, it secretly uploads a zero-byte object whose key ends in / (for example reports/). This placeholder is only there so the empty folder shows up in the UI.
Console steps to create an empty folder:
- Open the S3 console and click your bucket name.
- Click Create folder.
- Type a name (for example
reports) and click Create folder.
CLI equivalent (the zero-byte placeholder object):
aws s3api put-object --bucket my-app-data --key reports/
Avoid these zero-byte placeholders in automated pipelines. They can confuse code that lists objects, and lifecycle or sync tools may treat the
reports/object as real data. Just upload objects with the full key you want.
When to design key names deliberately
Key naming is one of the few S3 decisions that is hard to change later, so think about it up front. Two things make prefixes matter beyond aesthetics:
- Listing and filtering operate on prefixes.
ListObjectsV2,aws s3 sync, and many tools filter by prefix. A clean, predictable prefix scheme (liketenant-id/year/month/) makes targeted listing cheap and fast. - Lifecycle and replication rules target prefixes. A rule that transitions
logs/to Glacier after 30 days only matches keys beginning withlogs/. If your logs are scattered under inconsistent prefixes, the rule silently misses them.
Do I still need to randomize prefixes for performance?
No longer. Older guidance told you to add random hash prefixes to spread load. As of 2018, S3 automatically scales request throughput per prefix — at least 3,500 PUT/COPY/POST/DELETE and 5,500 GET/HEAD requests per second per prefix. You can still raise total throughput by spreading objects across multiple prefixes, but you should choose prefixes for organization and rule targeting, not for hashing tricks.
Key naming compared
| Approach | Example key | When to use | Watch out for |
|---|---|---|---|
| Date-partitioned | logs/2026/06/15/app.log | Time-series data, logs, lifecycle expiry by date | Listing “all of June” needs the 2026/06/ prefix |
| Tenant-partitioned | acme-corp/uploads/file.png | Multi-tenant apps, per-tenant lifecycle or access | Per-tenant policies must match the exact prefix |
| Flat / opaque IDs | a1b2c3d4-uuid.bin | Content-addressed blobs, no human browsing | No meaningful prefix grouping for rules |
| Mimicking a deep tree | app/users/123/photos/2026/jun/x.jpg | Rarely ideal | Deep nesting adds no benefit and clutters listings |
Best practices
- Treat keys as the single source of truth — there are no folders, only key strings and the prefixes derived from them.
- Choose a prefix scheme that matches how you will list, expire, and replicate data, not how a desktop file manager looks.
- Use a consistent delimiter (
/) so prefix grouping and lifecycle rules behave predictably. - Avoid creating zero-byte folder placeholder objects in code; upload objects with their full key instead.
- Do not add random hash prefixes for performance — S3 scales per prefix automatically. Spread across prefixes only if you genuinely exceed per-prefix request limits.
- Keep keys under 1,024 bytes and prefer URL-safe characters to avoid encoding surprises in URLs and tools.