Images, audio, and video don't belong in your database. This unit is how to store, process, and serve large binary assets — a recurring theme in your topic list.
⏱ 30 minPrereq: Units 08, 10You'll be able to: design an upload→process→serve media flow
By the end of this unit
Explain why blobs go in object storage, not a relational DB.
Use pre-signed URLs to upload/download without proxying bytes through your servers.
Design an async media pipeline: transcoding, compression, thumbnails.
Serve media at scale via CDN, with storage tiering for cost.
Why object storage
Object storage (S3, GCS, Azure Blob) stores arbitrary blobs by key with virtually unlimited capacity, built-in durability (multi-AZ replication), and a flat namespace. Databases are for queryable, structured metadata; blobs in a DB bloat it, kill cache efficiency, and slow backups. The pattern is universal:
The split to say out loud "The binary goes in object storage (S3); the database holds a row with the object's key/URL plus metadata (owner, dimensions, created_at). The DB stays small and fast; the blob store handles bulk and durability."
Object stores also offer tiered classes: hot (frequent access) → infrequent → cold/archive (Glacier). Old media that's rarely viewed tiers down automatically to cut cost — a great point for the "10-year storage" estimate from Unit 02.
Upload & download without proxying bytes
Don't stream gigabytes through your app servers. Use pre-signed URLs: your server authorizes the client and returns a short-lived URL the client uses to PUT directly to S3 (and GET directly, often via CDN). Your servers handle only auth and metadata — the heavy bytes go client↔storage.
The big bytes never touch your app servers — they go straight to the object store via a time-limited signed URL.
The media processing pipeline
After upload, heavy processing runs asynchronously (Unit 08): the upload completes fast, a job is enqueued, and workers do the slow work.
Transcoding: convert video/audio into multiple codecs/resolutions (e.g., 240p–4K) for adaptive bitrate streaming (HLS/DASH) so playback adjusts to the viewer's bandwidth.
Compression: shrink files (WebP/AVIF for images, H.264/H.265/AV1 for video) to cut storage and bandwidth with acceptable quality loss.
Thumbnails / variants: pre-generate sizes (feed, profile, full) so clients fetch the right one — no on-the-fly resizing on the hot path.
Precompute, don't transform on read Generating variants at upload time (and caching them) keeps the read path cheap. On-the-fly resizing per request burns CPU and latency at exactly the wrong moment. A small on-the-fly image service behind a CDN is acceptable only if results are cached.
Serving at scale
Processed assets live in the object store and are served through a CDN (Unit 10) for low latency and origin offload. Use stable, versioned keys so the CDN caches aggressively, and signed URLs / token auth if the content is private. The DB just returns the URL; the CDN does the rest.
Quick check
A teammate proposes storing uploaded videos as BLOBs in PostgreSQL. The main problem?
Wrong tool. Databases can hold bytes but shouldn't: huge rows wreck cache hit rates, inflate backups, and cap scalability. Store the blob in S3 and keep a lightweight metadata row pointing to it.
Quick check
Why upload via a pre-signed URL instead of through your API server?
Direct transfer. The server only authorizes and hands back a short-lived URL; the client streams the file straight to S3. This keeps app servers stateless and light, and scales upload throughput independently.
Practice before you move on
Design the full media flow for the photo app: pre-signed upload, what the DB row stores, the async pipeline (compress + 3 thumbnail sizes + safety check), CDN serving, and how 10-year-old photos get cheaper to store. Narrate it as a 2-minute deep dive.