The Mystery of Folders on AWS S3
The difference between objects and files, and what the AWS Console really does when you press the "create folder" button.
At the risk of sounding obvious: buckets are not filesystems. Photo by Sixteen Miles Out on Unsplash
When learning about cloud ☁️ or talking to pernickety data engineers 👨💻, you’ve no doubt picked up that “object storage is not a file system” or that “there’s no such thing as folders on S3”. But what is the difference? Why does the difference matter? And most importantly: why do the AWS S3 Console (as well as GCP) have a “Create folder” button, and what does it do? Let’s find out!
Object storage ≠ file storage
The most defining difference between object storage and file storage is that there is no hierarchical structuring of files — there are no folders in object storage. Instead, there is just a “flat” set of named binary blobs that we could call files but refer to as objects instead. The set itself is referred to as a bucket.
The lack of hierarchy allows for buckets to achieve far greater size, durability and availability than conventional filesystems. The reason for this is technical: lack of hierarchy makes it easy for objects to be dispersed and replicated across different physical machines without any need for centralised bookkeeping.
Some object storage systems only allow storage, retrieval and deletion of objects by their name, also known as their key. However, most object storage systems, including S3, have some pretty powerful capabilities for object listing:
- S3 allows quick filtering of files by prefix
- S3 allows splitting object listings by a separator, most tools set
/as default by convention
Thanks to this capability, object storage systems can appear similar to filesystems, although differences remain (see below) — whether these are important depends on circumstances.
Folders in the AWS Console
Unfortunately, cloud vendors like to make things complicated. AWS introduced the concept of a “folder” in the AWS Console — their web UI for S3. Does this not contradict the above? Why yes, yes it does!

What does the create folder button do?
Let’s investigate what the “Create Folder” button does. Start by creating a bucket:
aws s3 mb t35tbuck3t --region eu-west-1
Now navigate to this bucket in the Console, and you’ll see a shiny button, “Create folder”. What gives? Folders on object storage? Let’s try pressing it.
We are creating a “folder” in our bucket, t35stbuck3t.
Something happened, but what? The Console tells us it created a folder, but that can’t be it — remember that folders do not exist! We can investigate using some more low-level API calls:
aws s3api list-objects --bucket t35tbuck3t
This returns:
{
"Contents": [
{
"Key": "path/",
"LastModified": "2022-03-21T15:39:25+00:00",
"ETag": "\"d41d8cd98f00b204e9800998ecf8427e\"",
"Size": 0,
"StorageClass": "STANDARD",
"Owner": {
"DisplayName": "...",
"ID": "..."
}
}
]
}
The Console made a single empty object named path/. This shows up in the Console as an empty folder, even though it is just a 0-byte object.
Creating folders using the CLI
We can use the CLI to achieve the same thing; let’s make a “folder” to/ “inside” path/:
aws s3api put-object --bucket t35tbuck3t --key path/to/
Confirm its successful creation in the Console:

Adding files to folders
Upload a file, object.txt, inside of the /path/to/ “folder”:
echo "testobject" | aws s3 cp - s3://t35tbuck3t/path/to/object.txt
You can see the object appearing inside the to/ folder you created. However, uploading a similar object to the path /path/two/object.txt without first creating a folder two/ works too:
echo "testobject" | aws s3 cp - s3://t35tbuck3t/path/two/object.txt
In this case, you can see both the folder two/ and the object object.txt inside appear.
Realize the truth and claim the power that is rightfully yours!
Remember — folders do not exist. The cp command creates objects, in this case, an object with key /path/two/object.txt inside of the set of objects called t35stbuck3t. The folder concept is just a useful lie resulting from the convention to split listings by the / character in the Console (and many other tools). Even though we never created the directory two/ in path/, the Console tells us it exists.
The “folder” two/ shows up, even though we did not create it.
In fact, we can remove objects s3://t35tbuck3t/path/ and s3://t35tbuck3t/path/to/ without it having any observable impact!
Difference in behaviour
From the Console, folders path/to/ and path/two/ look identical. However, they’re different and will behave differently: two disappears when the object inside is removed, while to can exist on its own 🤯.
We cannot see why from the Console, but we can by thinking. Or by simply listing the bucket’s objects:
aws s3api list-objects --bucket t35tbuck3t | jq '.Contents[].Key'
Result:
"path/"
"path/to/"
"path/to/object.txt"
"path/two/object.txt"
Indeed, path/to/ remains visible as a folder because there is an (empty) object with this name. Knowing this, path/two, which exists only as a prefix of path/two/object.txt, disappearing together with path/two/object.txt makes sense. Unfortunately, there is no way to discern the two situations from the Console.
Some more great ideas
Knowing that everything on S3 is just objects with weird names and that / is a legal character for use in object names might give you some pretty awesome ehrm I mean horrible ideas.
- It is possible to create non-zero-byte files ending on
/. Creating such objects isa great way to baffle your colleaguesalmost always a bad idea and looks confusing in the Console. You can even make this file unreachable (from the Console), e.g. by creating another file ending on two/characters.
aws s3api put-object \
--bucket t35tbuck3t \
--key horribleidea/ \
--body /dev/fd/0 <<<'this is probably a bad idea'
An object, horrible/, with a name ending on a slash — a bad idea!
- It is possible to have an object and a “folder” share the same name. This is also
absolutely hilariousconfusing and to be avoided.
aws s3api put-object --bucket t35tbuck3t --key path/
echo "testobject" | aws s3 cp — s3://t35tbuck3t/path/
An object “path” and a “folder” “path/” present in the same bucket — also a bad idea!
- The “Create folder” button in the Console (apparently) does some bonkers stuff behind the scenes, as for it to work, you need permission to list the relevant part of the bucket (
ListObjects), not just permission to use the PutObject action. IfListObjectsrequests are restricted to use/as a separator (often mentioned as a good idea by AWS, for example here and here), then the “Create folder” button will also not work 🤷♂️. The UI will incorrectly single out thes3:PutObjectaction as the culprit. (I confirmed this weird behaviour on 21/3/2022)
The “insufficient permissions” are, in this case, actually due to a condition put on the ListObjects action.
Conclusion
AWS introduced the folder concept to its S3 Console to make it more user-friendly, introducing a lot of unnecessary confusion in many cases.
A harmful truth is better than a useful lie. — Thomas Mann
That’s it! Now you know everything!
…
Still here?
More on buckets and filesystems
Curious how proper hierarchy differs from the ability to list prefixes? If other differences exist between objects and files, buckets and filesystems? Read on! There’s always more to know.
Objects versus files
- File metadata consists of a well-defined set of properties such as an owner and ownership bytes. Object metadata is typically more flexible, allowing the attachment of tags and other forms of user-defined metadata.
- Files can be modified and appended; objects in object storage systems are immutable. You cannot append to an object or rename an object, except through a sequence of copy and delete commands.
Both don’t have to be true. Some object storage systems, not S3 but e.g. Ceph, do allow for “appendable objects”; this usually comes at the cost of object versioning. Many filesystems allow for file extended attributes.
Buckets versus filesystems
- You can write objects (files) with lengthy prefixes within a bucket without first creating folders…. Because there are no folders!
- No folders implies no folder operations. Operations on a prefix are not a single operation but an operation on every individual matched object.
- No folders implies no folder properties and permissions. Within buckets, you cannot assign properties to a prefix and have them apply to objects sharing the prefix in the same way as on a filesystem.
The lack of move operations and folder-level operations is often hidden from you by higher-level operations in the CLI or SDK. However, you will definitely notice this when your “folder” has many objects: operations will take longer and become more expensive. In lieu of folder permissions, you can usually condition IAM policies or bucket policies on prefixes, but certain limitations apply.
Examples of filesystems and object stores
- Examples of traditional filesystems are ext4, ZFS, XFS, Btrfs, and NTFS. These are filesystems that are implemented on top of block storage. A set of desirable filesystem properties can be found in the POSIX standards. Properties expected from POSIX filesystems can be validated using tools like pjdfstest.
- The most well-known object storage systems are those offered by the cloud hyperscalers — AWS S3, Azure Blob Storage and Google Cloud Storage (GCS). Other object storage systems include Ceph Object Storage, seaweedfs, minio and many more.
- There also exist many distributed filesystems and network file systems, typically exposed through protocols such as NFS, SMB/CIFS or custom HTTP interfaces and FUSE modules. There are the fully managed hyperscaler solutions (AWS EFS, Azure Files, Google Filestore) but also many many other solutions such as MooseFS and LizardFS, Lustre, BeeGFS, SeaweedFS, Hadoop’s HDFS and even IPFS (InterPlanetary File System)!
Interfacing
- Object storage systems typically expose an HTTP interface (REST).
- Filesystems are typically managed by your OS kernel and interfaced with through system calls.
- Linux enables implementing userspace filesystems using FUSE. FUSE allows you to implement a filesystem on top of HTTP 😱 🤤.
Hybrid systems
The difference between object storage and file systems is not always clear-cut. Many storage solutions exhibit properties of both; many filesystems are not POSIX compliant. Many tools allow you to expose buckets or parts of a bucket as a POSIX-ish filesystem or folder through FUSE (gcfuse, rclone, s3fs-fuse, Goofys, …). Many programs will work with such “ish” filesystems just fine, while other systems might fail catastrophically, for example, because they rely on folder deletion being constant-time or atomic.
Layering
Object storage is generally considered more “low level” than file storage. A frequently seen pattern is implementing a filesystem or something filesystem-like on top of object storage by introducing a more centralised metadata layer component. Such layering underpins SeaweedFS Filer, CephFS, JuiceFS (Redis+S3) and many more filesystem servers. Azure Data Lake Storage Gen2 is similarly built on top of Blob Storage.