Amazon S3 via SDK: Buckets & Objects
Amazon S3 stores objects - files of any kind - inside globally named buckets.
Busca en todas las páginas de la documentación
Amazon S3 stores objects - files of any kind - inside globally named buckets.
This page runs the whole lifecycle from code: create a bucket, put an object, read it back, list a prefix, then delete the object and the bucket. Both SDKs mirror each other step for step.
Quick-reference recipe card - copy-paste ready.
# --- Python (boto3) ---
import boto3
s3 = boto3.client("s3", region_name="us-east-1")
s3.put_object(Bucket="my-unique-bucket", Key="notes/hello.txt", Body=b"hello world")
body = s3.get_object(Bucket="my-unique-bucket", Key="notes/hello.txt")["Body"].read()
print(body.decode())// --- TypeScript (AWS SDK v3) ---
import { S3Client, PutObjectCommand, GetObjectCommand } from "@aws-sdk/client-s3";
const s3 = new S3Client({ region: "us-east-1" });
await s3.send(new PutObjectCommand({ Bucket: "my-unique-bucket", Key: "notes/hello.txt", Body: "hello world" }));
const out = await s3.send(new GetObjectCommand({ Bucket: "my-unique-bucket", Key: "notes/hello.txt" }));
console.log(await out.Body.transformToString());When to reach for this:
Create a bucket, wait for it to exist, put and read an object, list the prefix, then clean up fully.
# --- Python (boto3) ---
import boto3
region = "us-east-1"
bucket = "my-unique-bucket-20260723"
s3 = boto3.client("s3", region_name=region)
# 1. Create the bucket (us-east-1 must NOT pass a LocationConstraint).
if region == "us-east-1":
s3.create_bucket(Bucket=bucket)
else:
s3.create_bucket(Bucket=bucket,
CreateBucketConfiguration={"LocationConstraint": region})
s3.get_waiter("bucket_exists").wait(Bucket=bucket)
# 2. Put and get an object.
s3.put_object(Bucket=bucket, Key="notes/hello.txt", Body=b"hello world")
body = s3.get_object(Bucket=bucket, Key="notes/hello.txt")["Body"].read()
print("read:", body.decode())
# 3. List the prefix.
for obj in s3.list_objects_v2(Bucket=bucket, Prefix="notes/").get("Contents", []):
print(obj["Key"], obj["Size"])
# 4. Clean up: objects first, then the bucket.
s3.delete_object(Bucket=bucket, Key="notes/hello.txt")
s3.delete_bucket(Bucket=bucket)// --- TypeScript (AWS SDK v3) ---
import {
S3Client, CreateBucketCommand, PutObjectCommand, GetObjectCommand,
ListObjectsV2Command, DeleteObjectCommand, DeleteBucketCommand, waitUntilBucketExists,
} from "@aws-sdk/client-s3";
const region = "us-east-1";
const bucket = "my-unique-bucket-20260723";
const s3 = new S3Client({ region });
// 1. Create the bucket (us-east-1 must NOT pass a LocationConstraint).
await s3.send(new CreateBucketCommand(
region === "us-east-1"
? { Bucket: bucket }
: { Bucket: bucket, CreateBucketConfiguration: { LocationConstraint: region } }
));
await waitUntilBucketExists({ client: s3, maxWaitTime: 60 }, { Bucket: bucket });
// 2. Put and get an object.
await s3.send(new PutObjectCommand({ Bucket: bucket, Key: "notes/hello.txt", Body: "hello world" }));
const got = await s3.send(new GetObjectCommand({ Bucket: bucket, Key: "notes/hello.txt" }));
console.log("read:", await got.Body!.transformToString());
// 3. List the prefix.
const list = await s3.send(new ListObjectsV2Command({ Bucket: bucket, Prefix: "notes/" }));
for (const obj of list.Contents ?? []) console.log(obj.Key, obj.Size);
// 4. Clean up: objects first, then the bucket.
await s3.send(new DeleteObjectCommand({ Bucket: bucket, Key: "notes/hello.txt" }));
await s3.send(new DeleteBucketCommand({ Bucket: bucket }));What this demonstrates:
us-east-1 must omit LocationConstraint, others must include it.PutObject accepts bytes, strings, or streams as the body..read() in boto3, transformToString() in SDK v3./ to look like a folder path - but S3 is flat, with no real directories.us-east-1 is the legacy default region, so its CreateBucket must not send a LocationConstraint; every other region must.ListObjectsV2 returns up to 1,000 keys per page and a continuation token; use a paginator for larger listings.Instead of public ACLs, generate a time-limited presigned URL that anyone with the link can use until it expires.
# --- Python (boto3) ---
url = s3.generate_presigned_url(
"get_object",
Params={"Bucket": bucket, "Key": "notes/hello.txt"},
ExpiresIn=900, # 15 minutes
)
print(url)// --- TypeScript (AWS SDK v3) ---
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";
const url = await getSignedUrl(
s3,
new GetObjectCommand({ Bucket: bucket, Key: "notes/hello.txt" }),
{ expiresIn: 900 }, // 15 minutes
);
console.log(url);The URL carries a short-lived signature, so you share access without opening the bucket to the public.
For large uploads and downloads, stream rather than buffer. boto3's upload_fileobj/download_fileobj and the v3 @aws-sdk/lib-storage Upload helper handle multipart transfers automatically.
us-east-1 fails; omitting it elsewhere puts the bucket in the wrong place. Fix: branch on region as shown, sending the constraint only outside us-east-1.BucketAlreadyExists. Fix: add an account- or date-based suffix to make the name unique.DeleteBucket fails if any object or version remains. Fix: delete all objects (and versions, if versioning is on) first..read() (boto3) or await transformToString() (SDK v3).notes/ as a prefix filter, not a folder you must create.| Alternative | Use When | Don't Use When |
|---|---|---|
| S3 via SDK (this page) | Object storage for files, backups, and assets | You need low-latency structured queries |
| EBS / EFS | Block or file storage attached to compute | Shareable, web-scale object storage |
| DynamoDB | Small structured records with fast key lookups | Large binary files or documents |
| S3 presigned URLs | Temporary, scoped sharing without public access | Long-lived public content (use CloudFront) |
| CloudFront + S3 | Serving public static content at the edge | Private, per-request access |
us-east-1 is the original default region, so its API requires you to omit LocationConstraint. Every other region requires you to include it. Branch on the region to handle both.
Bucket names are globally unique across all AWS accounts. A common name is likely taken. Add a unique suffix such as your account id or a date.
The body is a stream. In boto3 call ["Body"].read(); in SDK v3 call await Body.transformToString() for text or use a stream helper for binary.
A bucket must be empty first. Delete all objects, and if versioning is enabled, delete all object versions and delete markers, then delete the bucket.
No. S3 is a flat key-value store. Keys like notes/hello.txt just use / by convention, and Prefix filters by that string. There are no directories to create.
Generate a presigned URL with a short expiry. Anyone with the link can access that one object until it expires, with no change to bucket permissions.
Stream instead of buffering. Use boto3's upload_fileobj/download_fileobj or the v3 lib-storage Upload helper, which manage multipart transfers for you.
ListObjectsV2 returns up to 1,000 keys with a continuation token. Use a paginator (get_paginator in boto3, paginateListObjectsV2 in SDK v3) to walk all pages.
No. Writing to an existing key replaces the object entirely. If versioning is enabled, the old version is retained; otherwise it is overwritten.
Yes - storage is billed per GB-month, plus request and data-transfer charges. Clean up test buckets, and consider lifecycle rules to expire or tier old objects.
Stack versions: This page was written for boto3 1.43.x (Python 3.10+) and the AWS SDK for JavaScript v3 (Node.js 18+).
Revisado por Chris St. John·Última actualización: 24 jul 2026