ESC

Type to search the knowledge base.

Media CDN and Image Pipeline

Frontend-facing image/media pipeline design — upload, derivatives, CDN URLs, formats, and responsive delivery.

advanced4 min read
  • system-design
  • interview
  • architecture
  • cdn
  • images

Scope the problem

How media gets from upload → processing → CDN → responsive <img>/video with good LCP and cost control.

In scope: client upload UX boundaries, URL design, transforms, caching, formats.

Out of scope: building a codec company.

Pipeline overview

Client upload → object storage (S3)
      → processing worker (resize, strip EXIF, virus scan)
      → derivatives / on-the-fly transform edge
      → CDN
      → browser (srcset / video)

Upload (frontend contract)

  1. Request signed URL(s) from API
  2. PUT bytes direct to storage (not through app server)
  3. Confirm upload → enqueue processing
  4. UI shows local preview; swaps to CDN URL when ready

See Upload Large Files UX for multipart/resume.

type CreateUploadResponse = {
  uploadId: string;
  urls: { partNumber: number; url: string }[];
};

Derivative strategies

Approach Pros Cons
Pre-generate sizes predictable storage × variants
On-the-fly transform flexible (?w=800&q=75) CPU; need cache
Hybrid common sizes pre; rest on fly complexity

URL design:

https://cdn.example.com/i/{imageId}/w/{width}/f/{format}/v/{version}

Immutable version segment → long cache.

Formats & quality

  • Negotiate AVIF/WebP/JPEG via Accept or f=auto
  • Quality ladders; don’t ship 95 quality 4k to mobile
  • Strip EXIF for privacy (GPS)
  • Animated: GIF → muted MP4/WebM for size

Responsive delivery (browser)

<img
  alt="..."
  width="1200"
  height="800"
  srcset=".../w/400 400w, .../w/800 800w, .../w/1200 1200w"
  sizes="(max-width: 768px) 100vw, 600px"
  loading="lazy"
  decoding="async"
/>

LCP image: no lazy; fetchpriority="high".

CDN caching

Content Cache
Immutable derivative URL max-age=31536000, immutable
Original private or short; not hot path
Transform miss origin shield; then cache

Purge by tag when legal takedown required.

Video specifics

  • HLS/DASH manifests + segments on CDN
  • Signed URLs / cookies for paid content
  • Multiple renditions; player picks (ABR)
  • Thumbnails sprite sheets for scrubbing

Frontend performance checklist

  • Always width/height or aspect-ratio
  • Blurhash/LQIP placeholders
  • Don’t download full-res in grids
  • Cap concurrent image requests if needed
  • Use CDN domain (HTTP/2/3 connection reuse)

Security

  • AuthZ on upload and on private media signed URLs
  • Short TTL signatures; refresh on 403
  • Content-Type validation; don’t execute user SVG inline without sanitize
  • Hotlink protection optional

Cost controls

  • Max upload size/type
  • Rate limit transforms per IP
  • Prefer pre-gen for top N traffic images
  • Monitor bandwidth by product surface

Tradeoffs

  1. Pre-gen vs on-the-fly
  2. Single global CDN vs multi-vendor
  3. Client-side compression before upload vs quality loss
  4. Public bucket vs fully signed

Interview close

Direct-to-storage upload → process → immutable CDN URLs with width/format → srcset/sizes on client → long cache → signed private media. Call out LCP and EXIF privacy.

Operational checklist (interview)

When walking a whiteboard, name the handoffs:

  1. Client validates and requests a session
  2. Storage receives bytes via signed URL
  3. Worker derives variants / scans
  4. CDN serves immutable URLs
  5. App swaps preview for final assetId

Call out failure isolation: upload success ≠ media ready. UI must model processing as first-class, not a spinner on the wrong side of the network.

Frontend URL helper

function mediaUrl(
  id: string,
  opts: { w: number; format?: "auto" | "avif" | "webp" | "jpg"; v?: string }
) {
  const f = opts.format ?? "auto";
  const v = opts.v ?? "1";
  return `https://cdn.example.com/i/${id}/w/${opts.w}/f/${f}/v/${v}`;
}

Keep helpers in a shared package so marketing pages and app shells don’t invent divergent transform params (which fragment CDN caches).

Monitoring

Track transform cache hit ratio, 4xx on signed URLs, p95 upload complete time, and bytes egress by surface (feed vs PDP). Cost spikes often come from missing sizes attributes downloading oversized assets—not from CDN unit price alone.

Further reading