Stop 18 · Cloud & HostingTopics · 3/11

AWS S3

Part of the Backend Developer Roadmap

In short

Never keep user uploads on your server's disk. S3 stores any number of files, keeps redundant copies, and serves them over HTTPS while your app servers stay stateless.

Amazon's object storage service — the standard place to store files (uploads, backups, static assets) at massive scale with high durability, outside your application server.

The purple blob slides a box into one of many lockers in a tall wall of bank lockers.

Think of it like this

The bank locker room

A bank gives you a locker and a key. You don't care which wall it's in or how thick the steel is. You put things in, take things out, and the bank handles guards and backups. Buckets are your lockers, objects are what's inside.

Watch it happen

Uploading straight to S3

Browser
Your API
S3 bucket

POST /uploads/avatar

1/5The browser asks your API for permission to upload a profile photo.

The big ideas

What you need to know

Buckets and keys

A bucket holds objects. Each object has a key like invoices/2026/42.pdf. The slashes only look like folders.

Private by default

New buckets block public access. Share files with presigned URLs or a CDN, not by making the bucket public.

Presigned URLs

A time-limited signed link that lets someone upload or download one object without having AWS credentials.

Storage classes

Rarely read files can move to cheaper classes like Glacier using lifecycle rules. Retrieval gets slower and costs more.

See it in code

Walk through the code

ts
1import { S3Client, PutObjectCommand } from "@aws-sdk/client-s3";2import { getSignedUrl } from "@aws-sdk/s3-request-presigner";3 4const s3 = new S3Client({ region: "ap-south-1" });5 6app.post("/uploads/avatar", requireAuth, async (req, res) => {7  const key = `avatars/${req.user.id}.jpg`;8  const command = new PutObjectCommand({9    Bucket: process.env.BUCKET!,10    Key: key,11    ContentType: "image/jpeg",12  });13  const uploadUrl = await getSignedUrl(s3, command, { expiresIn: 300 });14  res.json({ uploadUrl, key });15});

1/4ap-south-1 is the Mumbai region, close to Indian users.

The browser then sends PUT to uploadUrl with the same Content-Type header. The bucket also needs a CORS rule allowing your site's origin.

Save yourself the pain

Common mistakes

Oops

Making the whole bucket public so images load.

Do this instead

Keep it private and serve through CloudFront or presigned GET URLs. Public buckets are a classic data leak.

Oops

Streaming every upload through your Express server.

Do this instead

Big files then eat your server's memory and bandwidth. Let the browser upload directly with a presigned URL.

Your mission

Direct-to-S3 uploads

~40 min

Quick check

Why does the API hand out a presigned URL instead of receiving the file itself?

Go deeper

  1. 1Upload and retrieve a file from an S3 bucket using the AWS SDK.
  2. 2Learn how to generate a signed URL for temporary, secure access to a private file.
  3. 3Configure a bucket for public read access for use as a simple CDN origin.

More topics at this stop

Stuck on this topic? Ask an Insider

Get 1:1 guidance from people who've walked this exact path — on the InsideEdge app.

Download
InsideEdge