
Amazon S3AuthorCloudBrum editorial teamLast reviewedReading time~12 minLevelBeginner to advanced
Amazon Web Services · Storage · Object storage
Storage you never have to size. You put files (objects) in a bucket and fetch them by name over HTTPS. AWS keeps the copies spread across data centres, so you don’t plan capacity. The choice that matters is the storage class: cheaper classes cost less to keep and more to read. Everything starts private, and most S3 horror stories are someone making it public.
On this page (17 sections)
Mind map: Amazon S3 at a glance
Free to share. The downloaded image includes the CloudBrum link.
Key features (summary)
- Objects, not filesYou store an object under a key such as invoices/2026/10/inv-1042.pdf. There are no real folders, only keys with slashes in them, and a single object can be up to 50 TB.
- A class for every access patternStandard for hot data, Intelligent-Tiering when you can’t predict it, the infrequent-access classes for backups, and three Glacier classes for archives. Express One Zone gives single-digit millisecond latency in one zone.
- Built to not lose dataS3 is designed for 11 nines of durability, and most classes keep copies in at least three Availability Zones. Reads after a write are consistent, including list calls.
- Versioning and Object LockKeep every version of an object so a bad overwrite or delete can be undone. Object Lock adds write-once-read-many retention for records that must not change.
- Lifecycle rulesMove data to a cheaper class after N days, expire it, and tidy up old versions and unfinished uploads, all without a script.
- Private by defaultNew buckets block public access, have ACLs switched off, and encrypt new objects with S3-managed keys. You choose when to loosen anything, and you can switch to KMS keys.
- Events when objects changeSend a notification to Lambda, SQS, SNS or EventBridge when something is created or removed, which is how a lot of serverless pipelines start.
- Replication and global reachCopy objects to another bucket in the same Region or a different one, and speed up long-distance uploads with Transfer Acceleration or multi-Region access points.
Basic concepts
- Bucket
- The container for your objects. Its name is unique across AWS, and it lives in one Region.
- Object
- A piece of data plus its key, metadata and (if you use it) a version ID.
- Key and prefix
- The key is the object’s full name. A prefix is the leading part up to a slash, and it behaves like a folder in the console but isn’t one.
- Storage class
- How S3 keeps and charges for the object, from Standard to Glacier Deep Archive. You pick it per object.
- Versioning
- When on, every overwrite or delete keeps the older copy. A delete just adds a delete marker on top.
- Lifecycle rule
- A bucket-level instruction such as move to Standard-IA after 30 days, or delete noncurrent versions after 90.
- Bucket policy
- A JSON policy attached to the bucket that says who may do what, including conditions such as TLS only or a specific VPC endpoint.
- Block Public Access
- A set of switches, at account or bucket level, that overrides any policy or ACL that would make data public.
- Presigned URL
- A temporary link signed with your credentials. Whoever holds it can upload or download one object until it expires.
- Access point
- A named door into a bucket with its own policy, handy when many teams or apps share one large bucket.
- Multipart upload
- Large objects sent in parts, in parallel, and assembled by S3. Up to 10,000 parts of 5 MiB to 5 GiB each.
- Object Lock
- Write-once-read-many protection. Retention mode and a hold stop an object being deleted or changed for a set time.
- Event notification
- A message sent when an object is created, removed or restored. The target is Lambda, SQS, SNS or EventBridge.
- Replication
- Automatic copying of new objects to another bucket, in the same Region (SRR) or a different one (CRR), usually with versioning on both.
How to create & configure it
Set up a private bucket from the AWS console
- Pick the Region firstOpen S3 and check the Region in the top bar. Choose the one closest to the people and services that use the data. You can’t move a bucket later without copying everything.
- Name the bucketGeneral purpose bucket, then a name that’s unique across AWS, lower case, 3 to 63 characters. Include something that tells you what it is, such as acme-prod-invoices-ap-south-1.
- Leave Block Public Access onIt’s ticked by default. Keep it ticked. If a website really has to serve files publicly, put CloudFront in front instead of opening the bucket.
- Turn on versioningIt costs a little extra for old copies, and it’s the cheapest insurance you can buy against deleting the wrong thing.
- Check the encryptionNew objects get S3-managed keys (SSE-S3) automatically. Choose SSE-KMS if you need your own key, an audit trail of key use, or the ability to disable access by disabling the key.
- Upload somethingDrag a file into the bucket. For anything over a few hundred megabytes use the CLI or an SDK, which upload in parts and retry failed ones.
- Add a lifecycle ruleUnder Management, create a rule: move current objects to a cheaper class after the period that matches your reads, delete noncurrent versions after 90 days, and abort incomplete multipart uploads after 7 days.
- Write the access downGrant your application a role with just s3:GetObject and s3:PutObject on the prefix it needs. Add a bucket policy that denies any request not using TLS.
- Watch itSwitch on CloudWatch request metrics for the busy prefixes, add S3 Storage Lens, and set a budget alert so you hear about a runaway job before the invoice.
Tip: when the console steps work, capture them as code (CloudFormation, the CDK or Terraform, see the code references) so every environment gets the same safe settings and a typo shows up in review.
Common issues after configuration
| Symptom | Likely cause | What to check / fix |
|---|---|---|
| 403 AccessDenied on a bucket you own | The role or user lacks the permission, or a policy or Block Public Access is overriding it | Read the error for the action and resource, then check three places: the caller’s IAM policy, the bucket policy, and any SCP. If the objects are encrypted with KMS, the caller needs permission on the key too. |
| NoSuchBucket or NoSuchKey | Wrong name, Region or key | Capital letters and a leading slash both matter in a key, so Photo.jpg and /photo.jpg are different objects. Check the Region too: a bucket in another Region answers with a redirect or an error, depending on the client. |
| SignatureDoesNotMatch | The request was altered or signed with the wrong credentials or Region | Look for a proxy that rewrites headers, a clock that’s more than a few minutes out, or an SDK using the wrong Region or signing version. |
| Presigned URL says it has expired | The link lifetime is shorter than you think, or the credentials behind it expired first | A URL can’t outlive the temporary credentials that signed it. Sign with a role session that lasts at least as long as the link, or sign with long-term credentials in a safe place. |
| 503 Slow Down | Request rate over what a prefix is handling right now | S3 scales gradually. Retry with exponential backoff, spread keys over several prefixes, and use the SDK’s retry settings. |
| EntityTooLarge or an upload that never finishes | A single PUT over 5 GB, or a multipart upload with too few or too many parts | Use multipart. Parts are 5 MiB to 5 GiB, a maximum of 10,000 of them, so pick a part size that fits the object. |
| Bucket suddenly costs more | Old versions, incomplete uploads or a chatty application | Look at the Storage Lens dashboard and the bucket’s metrics. Add a rule to expire noncurrent versions and incomplete multipart uploads, and check request counts by prefix. |
| Can’t delete a bucket | It still has objects, versions or delete markers | Empty it first, including versions. A lifecycle rule that expires everything is the easy way for a big bucket. |
| Object can’t be changed or deleted | Object Lock retention or legal hold | That’s the point of it. Retention in compliance mode can’t be shortened by anyone, including the account root user. Plan retention periods carefully. |
| Restore from Glacier takes hours | Flexible Retrieval or Deep Archive need a restore request | Request a restore, choose a speed tier, and wait. If you need data in milliseconds, store it in Glacier Instant Retrieval instead. |
| Browser blocks access from your site | CORS isn’t configured | Add a CORS rule to the bucket that names your origin and the methods and headers you use. Don’t use * except for truly public assets. |
| Replication isn’t copying old objects | Replication applies to new objects only | Use S3 Batch Replication for what already exists, and check that versioning is on for both buckets and that the replication role has the right permissions. |
Use cases: when and where to use it
Good fit
- Photos, video, PDFs and everything else your users upload
- Backups, logs and archives that you want to keep for years
- The data lake behind analytics, machine learning and Athena queries
- Static websites and single-page apps, behind CloudFront
- Software releases, build artefacts and package mirrors
- A drop zone for files that partners and devices send in
Consider something else
- A database-like workload with many small, random updates → a database or Amazon EFS, not S3
- A shared file system for servers → Amazon EFS or FSx
- Block storage for one server → Amazon EBS
- Moving files in and out of a managed fleet with SFTP → AWS Transfer Family in front of S3
- The same job on other clouds → compare Azure Blob Storage and Cloud Storage
Pros: why consider it?
Why teams choose it
- Practically unlimited space, so there’s nothing to size or patch
- Strong durability and consistent reads after writes
- Storage classes that follow how your data ages
- Plugs into almost everything on AWS, and most third-party tools speak the S3 API
- Fine-grained access control and good defaults on new buckets
- Cheap to store, and you pay nothing for space you don’t use
Trade-offs to weigh
- It’s an object store: no appending to a file and no partial in-place edits
- Request and data transfer charges surprise people more than the storage price does
- Policies, ACL history and Block Public Access interact in ways that take time to learn
- Infrequent-access and Glacier classes bill for reads and for a minimum stay
- Bucket names are global and can’t be changed
- Leaving AWS means copying the data out, and that transfer is billed
Common threats, vulnerabilities & risks
| Risk | Severity | Why it matters | Mitigation |
|---|---|---|---|
| A bucket or object made public by mistake | High | Public buckets are behind a long list of data leaks, usually through an old ACL or an over-wide policy. | Keep Block Public Access on at the account level, and review any exception in code review. |
| Over-broad IAM permissions | High | s3: on lets a leaked key read or wipe every bucket in the account. | Scope roles to named buckets and prefixes, and use conditions such as source VPC endpoint. |
| No versioning or backup for important data | High | A bug or a malicious delete is permanent if there’s no older copy. | Turn on versioning, and add replication or Object Lock for data you can’t recreate. |
| Unencrypted or weakly encrypted data | Medium | Defaults cover encryption at rest, but traffic over plain HTTP is still possible unless you refuse it. | Add a bucket policy that denies requests without TLS, and use KMS keys for sensitive data. |
| Presigned links shared too widely | Medium | Whoever has the link can use it until the clock runs out. | Short expiry, one object, one action, and access logging. |
| Delete of a bucket’s contents by a compromised account | Medium | Versioning alone can be undone by someone with delete-version rights. | Use MFA delete or Object Lock, and send CloudTrail data events somewhere the same account can’t change. |
| Silent cost growth | Medium | Old versions, unused buckets and cross-Region traffic keep billing without anyone noticing. | Lifecycle rules, Storage Lens, tagging and a budget alert. |
| Public access through a CloudFront origin or website setting | Low–Med | A bucket opened up just for a website stays open for everything else. | Use CloudFront with origin access control and keep the bucket private. |
| No audit trail | Low–Med | Without logs you can’t tell who read or deleted something, or when. | Enable CloudTrail data events for sensitive buckets and server access logs where needed. |
Performance optimisation
- Spread load over prefixes. Each partitioned prefix can take at least 3,500 write and 5,500 read requests a second, and the limits add up across prefixes.
- Use multipart upload for anything big, and run parts in parallel. The SDKs' transfer managers do this for you.
- Download large objects with byte-range requests in parallel, in chunks of about 8 to 16 MB.
- Put CloudFront in front of content that many people read, so most requests never reach the bucket.
- Use Transfer Acceleration for long-distance uploads, or run the client in the same Region as the bucket.
- Try S3 Express One Zone (directory buckets) when you need single-digit millisecond latency for many small requests, such as machine learning training data.
- Keep objects reasonably sized. Millions of tiny files mean millions of requests, so batch small files into larger ones where you can.
- Use an S3 gateway VPC endpoint so traffic from your VPC stays on the AWS network and avoids a NAT gateway.
Reduce monthly cost
FinOps is the habit of managing cloud spend together with engineering. These are the FinOps checks that matter most for Amazon S3.
- Match the storage class to real access. Look at Storage Lens and access logs before moving data, because retrieving from a cold class can cost more than you saved.
- Use Intelligent-Tiering when access is unpredictable. It moves objects on its own, with a small monitoring fee per object, and leaves tiny objects alone.
- Write lifecycle rules for every bucket: transitions, expiry, noncurrent versions and incomplete multipart uploads.
- Mind the minimums. Infrequent-access classes bill at least 128 KB per object and 30 days, and Glacier classes have 90 or 180 day minimums.
- Cut request costs by batching small objects, caching with CloudFront and avoiding polling LIST calls.
- Keep traffic inside AWS. A gateway VPC endpoint is free, and moving data between S3 and EC2 in the same Region doesn’t cost transfer fees.
- Watch cross-Region replication and copy jobs. They bill for both transfer and the second copy.
- Delete what you don’t need: abandoned buckets, old logs, noncurrent versions, and test data.
- Compress and use efficient formats such as Parquet for analytics. You pay for every byte stored and scanned.
- Tag buckets by team and product, and set a budget alert for S3 as a line item.
Treat the prices and free-tier terms here as examples from AWS's public pages. They vary by Region and they change, so check the live figures first (see Pricing).
Security optimisation
- Keep Block Public Access on for the account, and treat any exception as a reviewed change.
- Give each application its own IAM role with permissions on one bucket or prefix. Don’t hand out long-lived access keys.
- Add a bucket policy that denies requests not using TLS, and, for internal data, requests that don’t come through your VPC endpoint.
- Rely on the default SSE-S3 encryption for most data, and use SSE-KMS with a customer-managed key where you need key-level control and logs.
- Switch on versioning, and add MFA delete or Object Lock where deletes must be hard to do.
- Share one object through a presigned URL that expires soon, and leave the bucket closed.
- Log with CloudTrail data events and server access logs for sensitive buckets, and send them to a separate account.
- Scan for exposure with IAM Access Analyzer for S3 and Amazon Macie to find sensitive data in the wrong place.
- Keep ACLs off (the bucket owner enforced setting) so policies are the only way access is granted.
- Review who can create buckets and change policies, and use service control policies to stop the dangerous actions across accounts.
Governance & compliance
Guardrails
- Tagging rules for buckets (owner, environment, data class, cost centre) checked when a bucket is created
- A service control policy that denies turning off Block Public Access or disabling default encryption
- A shared template for buckets with logging, versioning, lifecycle and policy built in
- A data classification that decides which buckets need KMS keys, Object Lock or replication
Continuous checks (AWS Config)
- “s3-bucket-level-public-access-prohibited”
- “s3-bucket-ssl-requests-only”
- “s3-bucket-versioning-enabled”
- “s3-bucket-logging-enabled”
- “s3-default-encryption-kms” for sensitive buckets
Use AWS CloudTrail to see who changed a bucket or read an object, AWS Config for configuration history and rules, IAM Access Analyzer to find buckets shared outside the account, and AWS Artifact for compliance reports. S3 is in scope for many assurance programmes, but the duty is shared: AWS runs the service, and you own the policies, encryption choices, retention and data.
Reduce carbon footprint
- Keep less. Data nobody needs still sits on disks that use electricity, so deleting it is the simplest saving there is.
- Compress files and prefer compact formats such as Parquet, so there is less to store, copy and scan.
- Use lifecycle rules and Intelligent-Tiering so cold data sits in the classes meant for it.
- Cache popular objects at the edge, so one copy at the origin serves many readers.
- Put buckets near the people and services that read them, which also shortens the long-haul transfers.
- For big archives that nobody waits on, a Region with a cleaner power grid is an easy pick.
- The AWS Customer Carbon Footprint Tool estimates emissions for your account. See how it treats S3 before you quote a figure.
Pricing
Purchase options
Storage by class Per GB-month
Storage is billed per GB-month, and the price drops as the class gets colder, from Standard at the top to Glacier Deep Archive at the bottom. The Region changes the rates.
Requests Per request
PUT, COPY, POST and LIST requests cost more than GET requests, and both are billed per thousand. Chatty applications can spend more on requests than on storage.
Retrieval and minimums Cold classes
Infrequent-access and Glacier classes charge to read data back, and bill a minimum period and object size. Cheap to keep can mean costly to touch.
Data transfer Out only
Data going into S3 is free. Data going out to the internet is billed after a monthly allowance, and cross-Region copies are billed too.
What you actually pay for
- Storage, by class and by the GB-month
- Requests (PUT, GET, LIST and others), per thousand
- Fees for reading back from infrequent-access and Glacier classes, and charges for leaving them early
- Data transferred out to the internet or to another Region
- Features: Intelligent-Tiering monitoring, replication, inventory, Storage Lens advanced metrics, S3 Object Lambda and others
Rates move with the Region and with time. As a rough guide, Standard storage in US East starts at about 2.3 cents per GB-month. Check the official Amazon S3 pricing page and the AWS Pricing Calculator for current figures, and read the AWS Free Tier page for what new accounts get.
Important code references
A private bucket for user uploads, set up as you’d want it in production: Block Public Access, versioning, encryption, a TLS-only policy and a lifecycle rule. Use the CLI or the Terraform tab to create the bucket. The Python and C# tabs put an invoice in it and hand back a link that stops working after 15 minutes. Swap in your own bucket name, Region and key.
# Names must be unique across AWS: change the bucket name. Mumbai is used as the example Region.
BUCKET=acme-uploads-123456789012
REGION=ap-south-1
aws s3api create-bucket --bucket $BUCKET --region $REGION \
--create-bucket-configuration LocationConstraint=$REGION
# Nothing public, ever
aws s3api put-public-access-block --bucket $BUCKET --public-access-block-configuration \
BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true
# Keep older versions so a bad overwrite can be undone
aws s3api put-bucket-versioning --bucket $BUCKET --versioning-configuration Status=Enabled
# SSE-S3 is already the default; stating it makes the intent visible
aws s3api put-bucket-encryption --bucket $BUCKET --server-side-encryption-configuration \
'{"Rules":[{"ApplyServerSideEncryptionByDefault":{"SSEAlgorithm":"AES256"},"BucketKeyEnabled":true}]}'
# Refuse any request that is not sent over TLS
aws s3api put-bucket-policy --bucket $BUCKET --policy '{
"Version": "2012-10-17",
"Statement": [{
"Sid": "DenyPlainHttp",
"Effect": "Deny",
"Principal": "*",
"Action": "s3:*",
"Resource": ["arn:aws:s3:::'$BUCKET'", "arn:aws:s3:::'$BUCKET'/*"],
"Condition": {"Bool": {"aws:SecureTransport": "false"}}
}]
}'
# Cheaper class after 30 days, old versions gone after 90, unfinished uploads cleaned up after 7
aws s3api put-bucket-lifecycle-configuration --bucket $BUCKET --lifecycle-configuration '{
"Rules": [{
"ID": "age-out",
"Status": "Enabled",
"Filter": {"Prefix": ""},
"Transitions": [{"Days": 30, "StorageClass": "STANDARD_IA"}],
"NoncurrentVersionExpiration": {"NoncurrentDays": 90},
"AbortIncompleteMultipartUpload": {"DaysAfterInitiation": 7}
}]
}'
# Upload, then make a link that works for 15 minutes
aws s3 cp ./invoice-1042.pdf s3://$BUCKET/invoices/2026/10/invoice-1042.pdf
aws s3 presign s3://$BUCKET/invoices/2026/10/invoice-1042.pdf --expires-in 900
# Assumes var.bucket_name (globally unique) and the AWS provider version 4 or later
resource "aws_s3_bucket" "uploads" {
bucket = var.bucket_name
}
resource "aws_s3_bucket_public_access_block" "uploads" {
bucket = aws_s3_bucket.uploads.id
block_public_acls = true
ignore_public_acls = true
block_public_policy = true
restrict_public_buckets = true
}
resource "aws_s3_bucket_ownership_controls" "uploads" {
bucket = aws_s3_bucket.uploads.id
rule {
object_ownership = "BucketOwnerEnforced" # ACLs off
}
}
resource "aws_s3_bucket_versioning" "uploads" {
bucket = aws_s3_bucket.uploads.id
versioning_configuration {
status = "Enabled"
}
}
resource "aws_s3_bucket_server_side_encryption_configuration" "uploads" {
bucket = aws_s3_bucket.uploads.id
rule {
apply_server_side_encryption_by_default {
sse_algorithm = "AES256"
}
bucket_key_enabled = true
}
}
data "aws_iam_policy_document" "tls_only" {
statement {
sid = "DenyPlainHttp"
effect = "Deny"
actions = ["s3:*"]
resources = [aws_s3_bucket.uploads.arn, "${aws_s3_bucket.uploads.arn}/*"]
principals {
type = "*"
identifiers = ["*"]
}
condition {
test = "Bool"
variable = "aws:SecureTransport"
values = ["false"]
}
}
}
resource "aws_s3_bucket_policy" "uploads" {
bucket = aws_s3_bucket.uploads.id
policy = data.aws_iam_policy_document.tls_only.json
depends_on = [aws_s3_bucket_public_access_block.uploads]
}
resource "aws_s3_bucket_lifecycle_configuration" "uploads" {
bucket = aws_s3_bucket.uploads.id
rule {
id = "age-out"
status = "Enabled"
filter {}
transition {
days = 30
storage_class = "STANDARD_IA"
}
noncurrent_version_expiration {
noncurrent_days = 90
}
abort_incomplete_multipart_upload {
days_after_initiation = 7
}
}
depends_on = [aws_s3_bucket_versioning.uploads]
}
# pip install boto3
import boto3
from botocore.config import Config
BUCKET = "acme-uploads-123456789012"
REGION = "ap-south-1"
# Signature version 4 is needed for presigned URLs in newer Regions
s3 = boto3.client("s3", region_name=REGION, config=Config(signature_version="s3v4"))
def upload_invoice(path, key):
"""Upload one file. upload_file switches to multipart on its own for large files."""
s3.upload_file(
path,
BUCKET,
key,
ExtraArgs={
"ContentType": "application/pdf",
"ServerSideEncryption": "AES256",
"Metadata": {"source": "billing-service"},
},
)
def download_link(key, seconds=900):
"""A URL that lets the holder fetch this one object until it expires."""
return s3.generate_presigned_url(
"get_object",
Params={"Bucket": BUCKET, "Key": key},
ExpiresIn=seconds,
)
def list_prefix(prefix):
"""List keys under a prefix, page by page, so a large listing doesn't need one huge response."""
keys = []
for page in s3.get_paginator("list_objects_v2").paginate(Bucket=BUCKET, Prefix=prefix):
keys.extend(item["Key"] for item in page.get("Contents", []))
return keys
if __name__ == "__main__":
key = "invoices/2026/10/invoice-1042.pdf"
upload_invoice("invoice-1042.pdf", key)
print(download_link(key))
print(list_prefix("invoices/2026/10/"))
// Program.cs: put an invoice in the bucket and print a 15-minute download link
// NuGet package: AWSSDK.S3
using Amazon;
using Amazon.S3;
using Amazon.S3.Model;
const string bucket = "acme-uploads-123456789012";
const string key = "invoices/2026/10/invoice-1042.pdf";
// Credentials come from the usual chain: environment, shared profile or the role the code runs under
using var s3 = new AmazonS3Client(RegionEndpoint.APSouth1);
// Upload; PutObject suits files up to a few hundred megabytes, and TransferUtility handles larger ones in parts
var put = new PutObjectRequest
{
BucketName = bucket,
Key = key,
FilePath = "invoice-1042.pdf",
ContentType = "application/pdf",
ServerSideEncryptionMethod = ServerSideEncryptionMethod.AES256
};
put.Metadata["source"] = "billing-service";
await s3.PutObjectAsync(put);
// A signed link that works until it expires
var link = s3.GetPreSignedURL(new GetPreSignedUrlRequest
{
BucketName = bucket,
Key = key,
Verb = HttpVerb.GET,
Expires = DateTime.UtcNow.AddMinutes(15)
});
Console.WriteLine(link);
// List what's under a prefix, one page at a time
string? token = null;
do
{
var page = await s3.ListObjectsV2Async(new ListObjectsV2Request { BucketName = bucket, Prefix = "invoices/2026/10/", ContinuationToken = token });
foreach (var item in page.S3Objects)
{
Console.WriteLine($"{item.Key} {item.Size} bytes");
}
token = page.IsTruncated == true ? page.NextContinuationToken : null;
} while (token is not null);
Best videos to explore
Short walkthrough videos for this service are being prepared. They will appear here and load only when you press play. Until then, follow CloudBrum on YouTube for new videos.
Interview questions
BasicWhat is Amazon S3?
It’s AWS’s object storage service. You create buckets and store objects in them, each with a key, and read them back over HTTPS with an SDK, the CLI or a plain URL. S3 spreads the data across facilities for durability, so you don’t manage disks or capacity.
BasicWhat is the difference between a bucket and an object?
A bucket is the named container, created in one Region. An object is one item inside it: the data, its key (the full name), metadata and optionally a version ID. The folder view in the console is just a display of key prefixes.
BasicName some S3 storage classes and when you’d use them.
Standard for data used often, Intelligent-Tiering when access is unpredictable, Standard-IA and One Zone-IA for infrequent access, Glacier Instant Retrieval, Flexible Retrieval and Deep Archive for archives, and Express One Zone when you need very low latency in a single zone. Colder classes cost less to store and more to read.
IntermediateHow do you make sure a bucket isn’t public?
Turn on Block Public Access at the account level, keep ACLs disabled with the bucket-owner-enforced setting, and check bucket policies for wildcard principals. Serve public content through CloudFront with origin access control instead of opening the bucket, and use IAM Access Analyzer to catch anything shared outside the account.
IntermediateHow does S3 keep objects safe from accidental deletion?
Versioning keeps older copies, so a delete only adds a delete marker. MFA delete asks for a second factor to remove a version, and Object Lock stops changes for a retention period. For disaster recovery, add replication to a bucket in another account or Region.
IntermediateWhat is a presigned URL and what is the risk?
It’s a time-limited link, signed with the creator’s credentials, that lets someone upload or download one object without having AWS access. The risk is that anyone who gets the link can use it until it expires, and it stops working when the signing credentials expire, so keep the lifetime short and the scope narrow.
AdvancedA bucket’s bill has doubled in two months and nobody added data. How do you find out why?
Look at Storage Lens and the Cost Explorer breakdown first: is it storage, requests, retrieval or transfer? Common causes are noncurrent versions piling up with no expiry rule, incomplete multipart uploads, a job listing the bucket constantly, or data being pulled out of a cold class. Fix it with lifecycle rules, caching and a change in how the application reads.
AdvancedYou need to keep records for seven years in a way no administrator can alter. What do you set up?
Create the bucket with Object Lock, use compliance mode with a seven-year default retention, turn on versioning, and limit who can change the lock settings. Replicate to a second bucket in another account, enable CloudTrail data events, and test a restore before you rely on it.
AdvancedHow would you move 200 TB from an on-premises system to S3?
It depends on the link and the deadline. With a fast and reliable network, use AWS DataSync or the CLI in parallel and validate checksums. If the network would take weeks, order a Snowball device, and keep the live data in sync with DataSync until cutover. Pick the destination class on day one so you don’t pay to transition it later.
AdvancedUploads to a busy prefix are returning 503 Slow Down. What do you do?
Retry with exponential backoff and jitter, which the SDKs do by default. Then spread the load, since the rate limits apply per partitioned prefix: add key prefixes, avoid putting every object under one hot prefix, and consider S3 Express One Zone if many small requests need very low latency. Make sure parallelism is raised gradually, not all at once.
Similar or alternative services on other clouds
| Capability | AWS | Azure | Google Cloud |
|---|---|---|---|
| Service | Amazon S3 | Azure Blob Storage | Cloud Storage |
| Where objects live | A bucket, tied to one Region | A container inside a storage account | A bucket in a region, dual-region or multi-region |
| Largest single object | 50 TB | About 190.7 TiB for a block blob | 5 TiB |
| Cheap tiers and how fast data comes back | Infrequent-access and Glacier Instant answer in milliseconds; Flexible and Deep Archive need a restore | Cool and Cold answer at once; Archive is offline and must be rehydrated | Nearline, Coldline and Archive all answer in milliseconds |
| Tiering on autopilot | Intelligent-Tiering | Lifecycle rules, including rules based on last access | Autoclass |
| Undoing a delete | Versioning, with MFA delete as an extra lock | Soft delete and versioning | Soft delete (seven days by default) and versioning |
| A link that expires | Presigned URL | Shared access signature (a user delegation SAS is the safer kind) | Signed URL |
| Run code when a file arrives | Event notifications to Lambda, SQS, SNS or EventBridge | Event Grid, often feeding Azure Functions | Pub/Sub notifications or Eventarc, feeding Cloud Run functions |
The same job does not always need object storage. A shared file system for servers is Amazon EFS or FSx territory, and a block disk for one server is Amazon EBS. If the data is mostly rows you query, a database or a warehouse is a better home.
Did you find this article helpful?
Your answer helps us improve this page for the next reader.
Sources and further reading
CloudBrum wrote this page in its own words, using the provider’s public documentation listed below as the reference. Features, limits, names and prices change, so confirm anything that matters on the provider’s own pages before you decide.
- What is Amazon S3?Amazon Web Services
- Amazon S3 storage classesAmazon Web Services
- Amazon S3 multipart upload limitsAmazon Web Services
- Amazon S3 increases the maximum object size to 50 TB (announcement)Amazon Web Services
- Optimizing Amazon S3 performance (design patterns)Amazon Web Services
- Block Public Access on and ACLs off for all new S3 buckets (April 2023 announcement)Amazon Web Services
- SSE-C turned off by default for new S3 buckets (April 2026 announcement)Amazon Web Services
- Security guidance for Amazon S3Amazon Web Services
- Amazon S3 pricingAmazon Web Services
- Terraform AWS provider: aws_s3_bucketHashiCorp
