Manage Files in S3 with Lifecycle Policies

Organize S3 buckets, enable versioning, and automate storage cost savings.

Introduction

30 Second Summary

Every company generates data that starts out important and gradually becomes less so. Think of it like paperwork on your desk: today's reports need to be right in front of you, last month's go in a filing cabinet, and last year's get boxed up in a storage unit.

In this project, you will build a file management system in Amazon S3 that organizes files into folders, tracks every change with versioning, and automatically moves aging data to cheaper storage to save costs.

What You'll Build

You will create an S3 bucket that simulates a real-world file management system for a small company, complete with organized folders, version tracking, and automated lifecycle policies that optimize storage costs without manual intervention.

By the end of this project, you'll have:

  • An S3 bucket with an organized folder-like structure using prefixes for logs, reports, and archives.
  • Multiple objects uploaded and managed using both the AWS Console and the AWS CLI.
  • Versioning enabled with multiple file versions visible, including the ability to restore a previous version.
  • Lifecycle policies that automatically transition objects through cheaper storage classes and auto-delete temporary files.
  • Secret Mission: Set up EventBridge notifications to get real-time alerts when objects are uploaded to your bucket.

Are there any prerequisites?

You'll need an AWS account and the AWS CLI installed and configured on your machine. If you haven't set those up yet, help me get started with AWS CLI setup.

Set Up Your S3 Bucket

Before you can manage files and automate storage, you need a place to put them. S3 buckets are the top-level containers in Amazon's object storage service. In this step, you'll create a bucket, organize it with a folder-like structure, and upload your first files.

In This Step, Get Ready To:
  • Create a general purpose S3 bucket with secure default settings.
  • Build a folder-like prefix structure to organize your files.
  • Upload sample files and explore their properties in the Console.
Create a General Purpose S3 Bucket

An S3 bucket is a container that holds your objects (files). Every bucket name must be globally unique across all AWS accounts, so you'll include your initials and today's date to make yours one-of-a-kind.

  • Open the S3 console.
  • Click Create bucket.
  • Enter a globally unique bucket name in the Bucket name field (e.g., mycompany-files-your-initials-todays-date).
  • Select a region (e.g., us-east-1).
  • Leave all other settings as default. Block all public access should be ON.
  • Click Create bucket.

Why do I need a globally unique name?

S3 bucket names share a single global namespace across every AWS account in the world. Bucket names must be 3-63 characters long, use only lowercase letters, numbers, and hyphens, and start with a letter or number. Adding your initials and a date keeps things unique and easy to identify.

Seeing "Bucket name already exists"?

Someone else already owns that exact name. Try adding extra characters like a random number to the end of your bucket name. If you're still stuck, help me pick a unique bucket name.

Create a Folder-Like Prefix Structure

Your company's files need organization. You'll create three folders to separate logs, reports, and archives. This mirrors how teams structure storage in production.

  • Click on your new bucket to open it.
  • Click Create folder.
  • Enter logs as the folder name and click Create folder.
  • Repeat this process to create two more folders: reports and archives.

You should now see three folders listed inside your bucket.

What is a prefix?

S3 doesn't actually have folders or directories. It's a flat storage system where every object has a unique key (its full name). When you create a "folder" called logs/, S3 is really just adding logs/ as a prefix to the object's key name.

For example, a file uploaded to the logs/ folder with the name app-log-jan.txt has the full key logs/app-log-jan.txt. The Console displays it as a folder for convenience, but under the hood it's all flat.

Upload Sample Files and Explore Their Properties

Now you'll populate your bucket with sample files. First, create a few small text files on your local machine.

  • Open a terminal and create three sample files.
echo "Application started successfully at 09:00 UTC" > app-log-jan.txt
echo "Q1 revenue: $1.2M, expenses: $800K" > quarterly-report-q1.txt
echo "Old database backup from last year" > old-backup.txt

What does this command do?

Each echo command writes a line of text into a new file. The > operator creates the file if it doesn't exist and writes the content into it.

Now upload each file to its matching folder in the S3 Console.

  • In the S3 Console, click on the logs/ folder.
  • Click Upload, then click Add files and select app-log-jan.txt from your local machine.
  • Click Upload.
  • Navigate back to your bucket root and repeat this process for the other two files:

Time to explore what S3 stores about each file.

  • Navigate to the logs/ folder and click on app-log-jan.txt to open its detail page.
  • Review the object's properties: Storage class, Size, Last modified, and Object URL.

What is a storage class?

Every object in S3 has a storage class that determines how much you pay to store and retrieve it. Your files default to S3 Standard, which costs $0.023/GB per month and provides millisecond retrieval. Later in this project, you'll set up lifecycle policies to automatically move aging files to cheaper storage classes.

Your bucket is set up with an organized structure and sample files ready to go. Next up, you'll learn how to manage these objects using the AWS CLI for faster, scriptable operations.

Manage Objects with the AWS CLI

In the previous step, you created your S3 bucket and uploaded files through the Console. The Console is great for visual exploration, but the AWS CLI is what practitioners use for automation, scripting, and managing files at scale. In this step, you'll learn to list, upload, download, copy, and delete objects entirely from the command line.

In This Step, Get Ready To:
  • Explore your bucket's prefix structure and objects from the CLI.
  • Upload, download, and copy individual files between prefixes.
  • Perform bulk operations and clean up objects using CLI commands.
List and Explore Your Bucket from the CLI

The aws s3 ls command lets you browse your bucket just like ls on a local file system. Since S3 uses a flat key structure, the CLI output reveals how prefixes work under the hood.

  • Open your terminal.
  • Run the following command to list the top-level prefixes in your bucket.
aws s3 ls s3://[[BUCKET="your-bucket-name"]]/

You should see your three prefixes listed: archives/, logs/, and reports/. Notice how S3 displays them with the PRE label, indicating they are prefixes, not actual directories.

  • Now list the objects inside the logs/ prefix.
aws s3 ls s3://[[BUCKET="your-bucket-name"]]/logs/
  • Run the following command with the --recursive flag to see every object in your bucket with its full key path.
aws s3 ls s3://[[BUCKET="your-bucket-name"]]/ --recursive

What does --recursive do?

Without --recursive, the ls command only shows the immediate level of prefixes and objects. With --recursive, it lists every single object across all prefixes, showing the full flat key structure that S3 actually uses. This is a quick way to get a complete inventory of your bucket.

Upload and Download Files Using the CLI

The aws s3 cp command works like a regular copy command, but it transfers files between your local machine and S3. You can also use it to copy objects between prefixes within the same bucket.

  • Create a new log file on your local machine.
echo "Server error at 14:32 UTC" > error-log-feb.txt
  • Upload the file to the logs/ prefix in your bucket.
aws s3 cp error-log-feb.txt s3://[[BUCKET="your-bucket-name"]]/logs/error-log-feb.txt

What does this command do?

The aws s3 cp command copies a file from a source to a destination. When the source is a local file path and the destination is an s3:// URI, it uploads the file. Swap them around and it downloads instead.

  • Download the quarterly report you uploaded earlier to your local machine.
aws s3 cp s3://[[BUCKET="your-bucket-name"]]/reports/quarterly-report-q1.txt ./downloaded-report.txt
  • Copy an object from one prefix to another within your bucket.
aws s3 cp s3://[[BUCKET="your-bucket-name"]]/logs/app-log-jan.txt s3://[[BUCKET="your-bucket-name"]]/archives/app-log-jan.txt

What happens when you copy between prefixes?

This creates a brand new object at the destination key. The original object at logs/app-log-jan.txt still exists. S3 copy is always a copy, not a move.

  • Head back to the S3 Console and open the archives/ folder to verify the copied object appears there alongside old-backup.txt.
Perform Bulk Operations and Clean Up Objects

Real-world S3 usage involves managing many files at once. The aws s3 sync command uploads an entire local directory to S3, and the aws s3api commands give you fine-grained control over object metadata.

  • Create a local folder with a couple of sample files to sync.
mkdir local-reports
echo "Q2 revenue summary" > local-reports/q2-report.txt
echo "Q3 revenue summary" > local-reports/q3-report.txt
  • Sync the entire local directory to the reports/ prefix in your bucket.
aws s3 sync ./local-reports s3://[[BUCKET="your-bucket-name"]]/reports/

What does aws s3 sync do?

The sync command compares the source and destination and only uploads files that are new or changed. If you run it again without making changes, nothing gets uploaded. This makes it efficient for keeping a remote copy of a directory up to date.

  • List all objects in your bucket along with their storage class and size using the aws s3api command.
aws s3api list-objects-v2 --bucket [[BUCKET="your-bucket-name"]] --query "Contents[].{Key:Key, StorageClass:StorageClass, Size:Size}"

What does this command do?

The aws s3api list-objects-v2 command is the lower-level API version of aws s3 ls. The --query flag uses JMESPath syntax to filter the JSON response, so you only see the key name, storage class, and size for each object.

All your objects should show STANDARD as their storage class. Later, you'll set up lifecycle policies to automatically transition objects to cheaper classes.

  • Delete the old backup file from the archives/ prefix.
aws s3 rm s3://[[BUCKET="your-bucket-name"]]/archives/old-backup.txt
  • Head back to the S3 Console and open the archives/ folder to confirm that old-backup.txt is gone.

Getting an access denied error?

Make sure your AWS CLI is configured with credentials that have S3 permissions. Run aws sts get-caller-identity to check which IAM identity your CLI is using. If the identity doesn't have S3 access, you'll need to update your IAM permissions. Help me troubleshoot my AWS CLI permissions.

You now have hands-on experience managing S3 objects from the command line. Next up, you'll enable versioning on your bucket to track every change to your files and protect against accidental deletions.

Enable Versioning and Track File Changes

You've been uploading and managing files across your bucket, but what happens if someone accidentally overwrites an important file? Right now, that data is gone forever. Versioning solves this by keeping a complete history of every change to every object in your bucket. In this step, you'll enable versioning and see how it protects your data.

In This Step, Get Ready To:
  • Enable versioning on your S3 bucket.
  • Create multiple versions of a file and view them in the Console.
  • Restore a previous version of a file using the CLI.
Enable Versioning on Your Bucket

Without versioning, uploading a file with the same key overwrites the previous file permanently. With versioning enabled, every change to an object creates a new version instead of replacing it. Even deletions are reversible because S3 adds a delete marker instead of permanently removing the object.

  • Open the S3 Console and navigate to your bucket.
  • Click the Properties tab.
  • Scroll down to Bucket Versioning and click Edit.
  • Select Enable and click Save changes.

Can I Turn Off Versioning Later?

Once you enable versioning on a bucket, you cannot fully disable it. You can only suspend it. Suspending versioning stops creating new versions for future uploads, but all existing versions remain in the bucket. This is important to know before enabling it on production buckets.

Create Multiple Versions of a File

Now that versioning is on, every upload to the same key creates a new version. Let's prove this by uploading the same file three times with different content.

  • Create a file called config.txt with initial content and upload it to your bucket.
echo "version 1" > config.txt && aws s3 cp config.txt s3://[[BUCKETNAME="your-bucket-name"]]/config.txt
  • Update the file and re-upload it.
echo "version 2 - updated settings" > config.txt && aws s3 cp config.txt s3://[[BUCKETNAME="your-bucket-name"]]/config.txt
  • Update and upload one more time.
echo "version 3 - final settings" > config.txt && aws s3 cp config.txt s3://[[BUCKETNAME="your-bucket-name"]]/config.txt

What Does This Command Do?

Each command does two things chained together with &&. First, echo writes new text content into config.txt on your local machine. Then aws s3 cp uploads the updated file to S3. Because versioning is enabled, S3 keeps the old version and stores the new one alongside it.

  • Go back to the S3 Console and navigate to config.txt in your bucket.
  • Toggle Show versions to reveal all three versions with their unique version IDs.

You should see three entries for config.txt, each with a different version ID, timestamp, and size. The most recent upload is the "current" version that S3 serves by default.

Restore a Previous Version

Versioning is most valuable when you need to recover from a mistake. Imagine someone overwrote your production config file with bad settings. You can restore any previous version by downloading it and re-uploading it.

  • In the S3 Console, make sure Show versions is toggled on for config.txt.
  • Find the version ID for version 1 (the oldest entry) and copy it.
  • Use the CLI to download that specific version.
aws s3api get-object --bucket [[BUCKETNAME="your-bucket-name"]] --key config.txt --version-id your-version-id-here restored-config.txt

What Does This Command Do?

The aws s3api get-object command downloads a specific version of an object by its version ID. The --version-id flag tells S3 exactly which version you want instead of the current one. The last argument, restored-config.txt, is the local filename where the downloaded content is saved.

  • Verify the content of the restored file.
cat restored-config.txt

You should see version 1 printed to the terminal. This confirms you successfully retrieved the original content.

  • Re-upload the restored file to make it the current version.
aws s3 cp restored-config.txt s3://[[BUCKETNAME="your-bucket-name"]]/config.txt

This creates a new version (version 4) that contains the original "version 1" content. S3 does not move or swap versions. It simply adds a new version that happens to have the old content.

Pro tip: versioning and lifecycle work together

In production, versioning can cause storage costs to grow quickly because every change creates a new copy. The best practice is to combine versioning with lifecycle policies that transition or expire noncurrent versions after a set number of days. You'll set up lifecycle policies in the next step.

Getting an "Access Denied" or "No Such Key" Error?

Double-check that you copied the version ID correctly from the Console. Version IDs are long strings and easy to truncate. Also make sure the bucket name and key (config.txt) match exactly. If you're still stuck, help me debug this error.

Your bucket now has a safety net. Every change is tracked and recoverable. Next up, you'll configure lifecycle policies to automatically move aging data to cheaper storage classes and keep costs under control.

Configure Lifecycle Policies for Cost Optimization

Your bucket now has versioning protecting files from accidental changes. But what about storage costs? In a real company, log files pile up fast. Data that was critical last week might sit untouched for months, quietly racking up charges at the full Standard rate.

S3 offers cheaper storage classes for data you access less often. Lifecycle policies automate the process of moving aging data to these cheaper tiers. In this step, you'll create rules that handle cost optimization without any manual intervention.

In This Step, Get Ready To:
  • Learn the S3 storage class hierarchy and how data "cools" over time.
  • Create a lifecycle rule for log files using the Console.
  • Create a lifecycle rule for temporary files using the CLI.
Understand S3 Storage Classes and the Cost Waterfall

Think of your data as having a "temperature." When a file is first created, it's hot. People access it frequently. Over weeks and months, that data cools down. Eventually, it becomes cold archive data that nobody touches but still needs to be kept.

S3 offers different storage classes that match each temperature level. The colder the class, the cheaper the storage. Here's the cost waterfall:

  • S3 Standard: $0.023/GB/month. For frequently accessed data. Millisecond retrieval.
  • S3 Standard-IA (Infrequent Access): $0.0125/GB/month. Millisecond retrieval, but with a 30-day minimum storage duration and 128 KB minimum billable object size.
  • S3 Glacier Flexible Retrieval: $0.0036/GB/month. Archive data with retrieval times of 1-12 hours. 90-day minimum storage duration.
  • S3 Glacier Deep Archive: $0.00099/GB/month. Long-term archive with retrieval times of 12-48 hours. 180-day minimum storage duration.

That's a massive cost difference. Glacier Deep Archive is over 20x cheaper than Standard. Lifecycle policies automate the transition down this waterfall so you never pay full price for data nobody is using.

Why not just pick the cheapest class from the start?

Cheaper storage classes come with trade-offs. Standard-IA charges you for a minimum of 30 days even if you delete the object after 1 day. Glacier can take hours to retrieve your data. Objects smaller than 128 KB won't be transitioned to IA because the metadata overhead would cost more than the savings.

The right strategy is to start with Standard for new data and let lifecycle policies move it to cheaper tiers as it ages.

Create a Lifecycle Rule for Log Files

Your first lifecycle rule will target the logs/ prefix. Log files are a perfect candidate for lifecycle policies. They're accessed heavily when troubleshooting recent issues, then rarely touched again.

  • In the S3 Console, open your bucket and click the Management tab.
  • Click Create lifecycle rule.
  • Enter log-lifecycle as the Lifecycle rule name.
  • Select Limit the scope of this rule using one or more filters.
  • In the Prefix field, enter logs/.

Now configure the transition actions. This is where you define the cost waterfall for your log files.

  • Under Lifecycle rule actions, check Transition current versions of objects between storage classes.
  • Add a transition to Standard-IA after 30 days.
  • Add another transition to Glacier Flexible Retrieval after 90 days.
  • Also check Expire current versions of objects and set it to 365 days.
  • Acknowledge the minimum storage duration warnings when prompted.
  • Click Create rule.

What does this lifecycle rule do?

You just created an automated cost waterfall for everything in your logs/ prefix. After 30 days, log files move to Standard-IA (about 46% cheaper). After 90 days, they move to Glacier Flexible Retrieval (about 84% cheaper). After 365 days, they're deleted entirely.

All of this happens automatically. No scripts, no cron jobs, no manual cleanup.

Create a Lifecycle Rule for Temporary Files Using the CLI

The Console is great for visual configuration, but in production, teams define lifecycle rules as JSON files. This makes rules version-controllable and repeatable across environments. Your second rule will target a tmp/ prefix and simply delete objects after 7 days.

  • Create a file called temp-lifecycle.json with the following content:
{
  "Rules": [
    {
      "ID": "cleanup-temp-files",
      "Status": "Enabled",
      "Filter": {
        "Prefix": "tmp/"
      },
      "Expiration": {
        "Days": 7
      }
    }
  ]
}

What does this JSON define?

This lifecycle configuration contains one rule. The Filter limits the rule to objects whose keys start with tmp/. The Expiration block tells S3 to delete matching objects 7 days after they were created. No transitions to cheaper storage. Just clean deletion.

This command will overwrite your Console rule

The put-bucket-lifecycle-configuration command replaces the entire lifecycle configuration on the bucket. It does not add to existing rules. To keep both rules, you need to include your log-lifecycle rule in the same JSON file. Update your temp-lifecycle.json to include both rules before running the command.

  • Update temp-lifecycle.json to include both lifecycle rules:
{
  "Rules": [
    {
      "ID": "log-lifecycle",
      "Status": "Enabled",
      "Filter": {
        "Prefix": "logs/"
      },
      "Transitions": [
        {
          "Days": 30,
          "StorageClass": "STANDARD_IA"
        },
        {
          "Days": 90,
          "StorageClass": "GLACIER"
        }
      ],
      "Expiration": {
        "Days": 365
      }
    },
    {
      "ID": "cleanup-temp-files",
      "Status": "Enabled",
      "Filter": {
        "Prefix": "tmp/"
      },
      "Expiration": {
        "Days": 7
      }
    }
  ]
}
  • Apply the lifecycle configuration to your bucket:
aws s3api put-bucket-lifecycle-configuration --bucket [[BUCKETNAME="your-bucket-name"]] --lifecycle-configuration file://temp-lifecycle.json
  • Verify both rules are in place by checking the Console. Go to your bucket and click the Management tab.

You should see both log-lifecycle and cleanup-temp-files listed under lifecycle rules.

When do lifecycle rules actually run?

Lifecycle rules are evaluated once per day at midnight UTC. There can be a delay of 24-48 hours before actions take effect. You won't see objects transition immediately after creating a rule. In production, this daily evaluation is fine because lifecycle policies are designed for long-term cost optimization, not real-time operations.

Pro tip: free to create

Lifecycle rules themselves are free. You only pay per-request transition charges (about $0.01 per 1,000 requests) when objects actually move between storage classes. Since your test bucket has only a handful of objects, there's no cost impact here.

Your bucket now manages its own storage costs automatically. Next up, you'll verify everything is working together and explore how versioning and lifecycle policies complement each other.

Verify and Explore Your Storage Setup

You have a bucket with organized prefixes, versioned files, and lifecycle policies that automate cost optimization. Before wrapping up, it is worth verifying that everything is configured correctly. In this step, you will use the CLI and Console to inspect your full setup and understand how versioning and lifecycle policies work together in production.

In This Step, Get Ready To:
  • Review all lifecycle rules using both the CLI and Console.
  • Confirm versioning status and inspect object version history.
Review All Lifecycle Rules

Your bucket now has two lifecycle rules: one created through the Console for log files, and one applied via the CLI for temporary files. You can retrieve both rules in a single JSON output using the CLI.

  • Run the following command in your terminal to retrieve all lifecycle rules.
aws s3api get-bucket-lifecycle-configuration --bucket [[BUCKETNAME="your-bucket-name"]]

What should I see?

The output is a JSON object containing a Rules array. You should see two rules listed. The log-lifecycle rule targets the logs/ prefix with transitions to Standard-IA at 30 days, Glacier Flexible Retrieval at 90 days, and expiration at 365 days. The cleanup-temp-files rule targets the tmp/ prefix with expiration at 7 days.

  • Open the S3 Console and navigate to your bucket.
  • Click the Management tab to see both rules listed with their prefixes, transitions, and expiration settings.

How Do Multiple Lifecycle Rules Work Together?

In production, you would typically combine multiple rules into a single lifecycle configuration on a bucket. Each rule can target a different prefix or tag, so you can manage logs, temp files, and archives with separate policies all within one configuration. S3 evaluates all rules once per day and applies any matching actions.

Check Versioning Status and Object Details

Earlier you enabled versioning and created multiple versions of config.txt. Now you will confirm the versioning status programmatically and inspect the full version history of that file.

  • Run the following command to confirm versioning is enabled on your bucket.
aws s3api get-bucket-versioning --bucket [[BUCKETNAME="your-bucket-name"]]

What should I see?

The output should show "Status": "Enabled". If versioning had never been turned on, this command would return an empty response. Once enabled, versioning cannot be fully disabled. It can only be suspended.

  • Run the following command to list all versions of config.txt.
aws s3api list-object-versions --bucket [[BUCKETNAME="your-bucket-name"]] --prefix config.txt

What does this command do?

This command retrieves every version of objects matching the config.txt prefix. Each version has a unique VersionId, a Size in bytes, and a LastModified timestamp.

The most recent version is marked with "IsLatest": true. You should see three or four versions depending on whether you restored an earlier version in Step 3.

Pro tip: save costs on old versions

Versioning combined with lifecycle policies is a best practice in production. You can add a lifecycle rule that transitions or expires noncurrent versions to cheaper storage classes. This keeps your latest version readily accessible while automatically reducing costs on older versions you rarely need.

Your S3 storage system is now fully verified. You have confirmed that lifecycle rules are in place to automate cost optimization and that versioning is tracking every change to your files. Up next, you will take on a secret mission to make your bucket even smarter with event-driven notifications.

Secret mission

Add S3 Event Notifications with EventBridge

Your S3 bucket is organized and cost-optimized, but what happens when a new file lands in it? Right now, you would have to manually check. In this secret mission, you will set up Amazon EventBridge to automatically detect new uploads and log them, introducing you to event-driven architecture on AWS.

Before you go

Clean Up Your Resources

Decide whether to keep your resources running, pause them to come back later, or delete them entirely. This project uses S3, which is covered by the AWS Free Tier (5 GB storage, 20,000 GET requests, and 2,000 PUT requests per month for the first 12 months).

Resources you used:

  • 1 S3 bucket with objects, versioning enabled, and lifecycle policies configured.
  • Local text files created for uploading (app-log-jan.txt, config.txt, temp-lifecycle.json, etc.).
  • If you completed the Secret Mission: 1 EventBridge rule and 1 CloudWatch Log Group.

Keep everything running

No action needed. Choose this if you want to keep exploring S3 or plan to build on this project.

  • Your S3 bucket and its objects stay within Free Tier limits as long as you remain under 5 GB of total storage.
  • Lifecycle policies are free to create. Objects only transition when they meet the age criteria, and transition request costs are minimal (around $0.01 per 1,000 requests).
  • EventBridge covers the first 14 million custom events per month for free. CloudWatch Logs covers up to 5 GB of ingestion per month for free.

Pause - I'll come back to this later

S3 has no running compute to pause. Your bucket simply stores objects and you only pay for what you store. There is no "pause" action for S3.

  • If you want to reduce storage, delete any test files you no longer need from your bucket.
  • Your lifecycle policies will continue running automatically. Over time, they will transition objects to cheaper storage classes, which saves costs for you.
  • If you completed the Secret Mission, you can disable the EventBridge rule in the EventBridge console to stop processing events while keeping the rule for later.

Delete - I don't want to use this again

Remove all project resources and start fresh. Follow these steps to fully clean up.

  • Empty the bucket by running aws s3 rm s3://your-bucket-name --recursive in your terminal.
  • Since versioning is enabled, you also need to delete all object versions. Go to the S3 Console, open your bucket, toggle Show versions, select all items, and delete them.
  • Delete the bucket by running aws s3 rb s3://your-bucket-name in your terminal.
  • If you completed the Secret Mission, delete your EventBridge rule in the EventBridge console.
  • If you created a CloudWatch Log Group, delete it in the CloudWatch console.
  • Delete any local files you created during the project (config.txt, temp-lifecycle.json, downloaded-report.txt, etc.).

Why Do I Need to Delete Versions Separately?

When versioning is enabled, running aws s3 rm --recursive only adds delete markers to your objects. It does not permanently remove the underlying versions. You must delete all versions before S3 allows you to delete the bucket itself.

Mission accomplished

That's a Wrap!

Nice work! You just built a complete S3 storage management system from scratch. You now know how to organize, manage, and optimize cloud storage the way teams do it in production.

Here's what you accomplished:

  • Created an S3 bucket with an organized prefix structure and managed objects using both the AWS Console and the CLI.
  • Enabled versioning to track file changes over time and restored a previous version of an object.
  • Configured lifecycle policies that automatically transition objects through cheaper storage classes and auto-delete temporary files.
  • Set up EventBridge notifications for real-time alerts when objects are uploaded to your bucket.

Ready to quiz yourself?