DEV Community

Cover image for S3 Has No Folders. Here's What You're Really Using.
Rahimah Sulayman
Rahimah Sulayman

Posted on

S3 Has No Folders. Here's What You're Really Using.

Overview

In my previous article, I created an S3 bucket and uploaded a single object. This time I'm organizing that bucket: creating folders, uploading multiple files at once, moving an object between folders, and finally deleting the bucket.

Along the way I'll explain a fact that trips up many people: Amazon S3 doesn't have folders. What the console shows you is something else, and once you understand it, a lot of S3 behavior starts to make sense.

By the end of this article, you'll be able to:

  • Create folders (and nested folders) in a bucket
  • Upload several files in one go
  • Explain what a prefix is and how it differs from a real folder
  • Move an object from one folder to another, and understand what S3 does behind the scenes
  • Empty and delete a bucket correctly

Where we're starting

I'm using the same bucket from the first article, aws-lab1-rahimah, which currently holds one object, datacenter.png.

Step 1: Create a folder

Inside the bucket, I clicked Create folder. The form asks for a folder name, so I entered food. Notice the hint under the field: folder names can't contain a /, because S3 uses that character itself to mark folder boundaries (more on that shortly).

Create folder page with the name food

The page also has a Server-side encryption section with two options:

  • Don't specify an encryption key: the folder uses the bucket's default encryption setting. I kept this one.
  • Specify an encryption key: choose a key just for this folder object.

Two warnings on that page are worth reading. The encryption settings apply only to the folder object itself, not to the files you later put inside it. And if your bucket policy requires a specific encryption key, you must specify that same key here, or folder creation will fail.

After clicking Create folder, S3 confirmed with a green banner, and the bucket now lists Objects (2): datacenter.png and food/. The Type column shows Folder for food/.

create folder

Successfully created folder food

Opening food/ shows an empty folder: Objects (0).

The empty food/ folder

So what is a "folder" in S3?

Here's the important part. S3 uses a flat structure. There is a bucket, and inside it there are objects. That's it. There are no real directories nested inside each other.

What the console calls a folder is built from three ideas:

  • Key: the full name of an object. A file I upload into food/ has the key food/burger.png, not just burger.png.
  • Prefix: the beginning part of a key. For food/burger.png, the prefix is food/.
  • Delimiter: the character that separates the parts of a key. In S3, it's the forward slash /.

When you click Create folder, S3 creates a tiny, empty object whose key ends in / (here, food/). The console then uses the / delimiter to display objects with the same prefix as if they lived in a folder. It's a presentation layer that makes a flat store feel familiar.

Coming from Azure? It works much the same way in Blob Storage. A container holds blobs in a flat namespace, and "folders" are just / characters in blob names (virtual directories). Real directories only appear when you enable the hierarchical namespace on a storage account (Data Lake Storage Gen2).

Step 2: Upload multiple files into the folder

With food/ open, I clicked Upload, then Add files. In the file picker, I selected three images at once: burger.png, cake.png and pizza.png.

Selecting three files in the file picker

The Upload page lists all three (3 total, 8.2 MB), and the Destination is now s3://aws-lab1-rahimah/food/. That path is the S3 URI of the folder, which is exactly the prefix the files will receive.

Three files ready to upload to the food/ prefix

I clicked Upload, and the status page reported Upload succeeded: 3 files, 8.2 MB, 100%, with 0 failures.

Upload succeeded for all three files

Back at the bucket's root, there are still only two entries, datacenter.png and food/. The three new files live inside the folder.

The bucket root still shows two entries

Opening food/ shows Objects (3): burger.png, cake.png and pizza.png, each with the Standard storage class and its own last-modified time.

Three objects inside food/

Step 3: Open a file and see the prefix in the URL

To prove the prefix idea, I selected burger.png and clicked Open. The image loaded in a new tab, and the address bar shows the key right in the path:

https://aws-lab1-rahimah.s3.eu-north-1.amazonaws.com/food/burger.png?X-Amz-Algorithm=...
Enter fullscreen mode Exit fullscreen mode

burger.png opened in the browser, with food/ visible in the URL

See food/burger.png? That's the full key. There's no directory lookup involved. The long X-Amz-... parameters after it are the presigned URL signature I covered in the first article, which is why the file opens even though the bucket is private.

Step 4: Create a nested folder

Next, I wanted a sub-folder. Inside food/, I clicked Create folder again and named it menu. S3 confirmed with Successfully created folder "menu".

Now food/ contains burger.png, cake.png, pizza.png and the new menu/ folder. The key of that new folder is food/menu/, which is just a longer prefix. Nesting folders only means chaining more prefixes with /.

I deleted the datacenter.png and created an empty folder called menu/.

Step 5: Move a file into the new folder

I wanted cake.png to live in menu/. I ticked the checkbox next to cake.png and opened the Actions menu. It offers a lot of options:

  • Download as and Share with a presigned URL
  • Calculate total size
  • Copy and Move
  • Query with S3 Select
  • Under Edit actions: Rename object, Edit storage class, Edit server-side encryption, Edit tags, and Make public using ACL

The Actions menu with cake.png selected

I chose Move. The page opens with an important note at the top: this action creates a copy of the object with a new last-modified date, and depending on the bucket's versioning status, a delete marker will be inserted or the original object will be permanently deleted. Keep that sentence in mind, because it explains what move really does (more below).

the move page

The Destination field expects an S3 path in the format s3://bucket-name/optional-prefix/. You can type it, or click Browse S3 and navigate to the folder. I used Browse S3, went into aws-lab1-rahimah > food/, and selected the menu/ folder.

Browsing S3 to pick the menu/ folder

The browser also lets you open menu/ to check what's inside. At this point, it says there are no objects under this path, which is expected for a brand-new folder.

Inside menu/ in the destination browser

After clicking Choose destination, the form filled itself in:

  • Destination: s3://aws-lab1-rahimah/food/menu/
  • Destination bucket name: aws-lab1-rahimah
  • Destination prefix: food/menu/

Below that, Destination details shows the settings of the target bucket: Bucket Versioning is Disabled, Default encryption is SSE-S3, and Object Lock is Disabled. Because versioning is off, the console shows a recommendation to enable it. The Specified objects table confirms the one file being moved, cake.png (2.7 MB).

Last, Additional copy settings offers three choices. I kept the default, Copy source settings, which carries over the source object's storage class, tags, metadata and encryption. The other two let you skip those settings or specify new ones.

Move configuration before clicking Move

I clicked Move. The status page reported Successfully moved objects: 1 object, 2.7 MB, with 0 failures.

Successfully moved objects

Checking the results:

  • food/ now shows Objects (3): burger.png, menu/ and pizza.png. cake.png is gone from here.

food/ after the move

  • menu/ shows Objects (1): cake.png.

cake.png now lives in menu/

What "move" really does

Look at the Last modified time on the moved file. It changed to a newer timestamp than when I originally uploaded it. That's the giveaway: S3 has no true "move" or "rename" operation. The console does two steps for you:

  1. Copy the object to the new key (food/cake.png becomes food/menu/cake.png).
  2. Delete the original.

This matters for two reasons. First, because versioning was disabled on this bucket, the original was permanently deleted. If versioning were enabled, S3 would insert a delete marker instead, and the old version could be recovered. Second, the same logic applies to Rename object: it's also a copy followed by a delete, since a rename just means giving the object a new key.

For anything you can't afford to lose, enable versioning before you start moving things around.

Step 6: Delete the bucket

When the lab is finished, clean up so nothing lingers in your account. On the General purpose buckets page, I selected the radio button next to aws-lab1-rahimah. The toolbar offers Copy ARN, Empty, Delete and Create bucket.

The bucket list with the bucket selected

I clicked Delete first, and S3 stopped me with this error: "This bucket is not empty. Buckets must be empty before they can be deleted." The page also asks you to type the bucket's name to confirm deletion, but the Delete bucket button stays disabled until the bucket is empty.

Delete bucket error: This bucket is not empty

The solution is to empty the bucket first:

  1. Click Empty bucket (on that error banner, or Empty on the bucket list). Or go back to the bucket, select the objects and click delete.
  2. Confirm by typing permanently delete when prompted, then click Empty. This can never be retrieved because versioning is not enabled.

permanently delete

  1. Return to Delete bucket, type aws-lab1-rahimah in the confirmation field, and click Delete bucket.

delete bucket

Emptying removes every object, including the folder objects, and it cannot be undone. That's why S3 makes you confirm twice.

successful deletion

Key takeaways

  • S3 has no real folders. A "folder" is a prefix that the console displays using the / delimiter.
  • An object's key is its full name, including the prefix. burger.png inside food/ has the key food/burger.png.
  • Creating a folder just creates a small, empty object whose key ends in /.
  • You can upload several files at once, and they all receive the destination folder's prefix.
  • Move and Rename are really copy + delete, which is why the last-modified date changes.
  • With versioning disabled, a move permanently removes the original. With versioning enabled, a delete marker is added instead.
  • A bucket must be emptied before it can be deleted.
  • In Azure terms, this is the same flat-namespace model as Blob Storage virtual directories.

Conclusion

Folders in S3 are a convenience, not a structure. Once you think in terms of keys and prefixes, things like moving files, setting lifecycle rules and writing IAM policies for food/* all make sense, because they all work on prefixes.

Next up in this series, I'll look at S3 permissions and what it takes to make an object public safely.

Which S3 feature should I cover after that: versioning, lifecycle rules or static website hosting? Let me know in the comments.

Top comments (1)

Collapse
 
rahimah_dev profile image
Rahimah Sulayman •

A detail that surprises people: the food/ "folder" doesn't even need to exist.

Upload a file straight to the key food/menu/cake.png using the CLI:

aws s3 cp cake.png s3://aws-lab1-rahimah/food/menu/cake.png

The console will still show food/ and menu/ as folders, even though neither was ever created. They're just prefixes, and the console draws the folders for you. The Create folder button only adds a tiny empty placeholder object whose key ends in /.

It also explains why "renaming a folder" is a bigger job than it looks. There's nothing to rename, so changing food/ to meals/ means S3 has to copy and delete every object under that prefix, one by one. A prefix with 10,000 files means 10,000 copy + delete operations.

Have you ever hit that on a large bucket? And which should I cover next: versioning, lifecycle rules or static website hosting?