# Thumbnail Service Low-Level Design: On-Demand Generation, URL-Based Params, and Cache Hierarchy

Source: https://www.techinterview.org/post/3233469498/lld-thumbnail-service/
Updated: 2026-06-30 · techinterview.org

## URL Scheme and Parameter Design

A thumbnail service exposes a clean HTTP API for on-demand image transformation. The URL encodes all transformation parameters:


```
/thumbnail?url=s3://bucket/originals/photo.jpg&w=300&h=200&fit=cover&format=webp
```

Parameters:

- `url` — source image location (S3 key or signed URL)

- `w`, `h` — target width and height in pixels

- `fit` — resize mode (cover, contain, fill, inside, outside)

- `format` — output format (webp, avif, jpeg, png)

- `q` — quality (1–100, default 80)

Critically, dimension values must be whitelisted to a set of allowed sizes (e.g., 100, 200, 300, 400, 600, 800, 1200). Accepting arbitrary dimensions creates a DoS vector: an attacker can generate millions of unique URLs with slightly different dimensions, each requiring a separate cache entry and generation pass.

## Fit Modes

Different use cases require different resize behaviors:

- **cover:** resize to fill the target dimensions, cropping excess. Output is always exactly w×h. Used for thumbnails in grids where consistent size is required.

- **contain:** resize to fit within target dimensions, preserving aspect ratio. Adds letterbox/pillarbox padding to fill. Used when full image must be visible.

- **fill:** stretch to exactly w×h ignoring aspect ratio. Rarely used.

- **inside:** resize so image fits within w×h, no upscaling. Output may be smaller than requested.

- **outside:** resize so image covers w×h, no downscaling. Output may be larger than requested.

## Format Selection and Modern Formats

Output format has a significant impact on file size and browser compatibility:

- **WebP:** ~30% smaller than JPEG at equivalent visual quality. Supported in all modern browsers (Chrome, Firefox, Safari 14+, Edge).

- **AVIF:** ~50% smaller than JPEG, even better than WebP. Supported in Chrome 85+, Firefox 93+, Safari 16+. Encoding is slower.

- **JPEG:** fallback for older browsers and non-photo content. Still required for Safari < 14.

- **PNG:** lossless, for images requiring transparency without WebP support.

Best practice: use the Accept header to detect browser capabilities and serve WebP/AVIF when supported, JPEG otherwise. This can be handled at the CDN layer (Cloudflare Image Resizing, AWS CloudFront Functions) or in the service itself.

## Cache Key Design

The cache key must be a deterministic, collision-free identifier for a specific (source, parameters) combination. Compute a hash of the normalized parameters:


```
cache_key = SHA256(canonical_url + ":" + w + ":" + h + ":" + fit + ":" + format + ":" + q)
```

Normalize before hashing: sort query parameters alphabetically, lowercase format strings, clamp quality to allowed range. The S3 output path becomes `/thumbnails/{first2_hex}/{cache_key}.{format}` — the two-character prefix distributes keys across S3 partitions.

## Generation Flow

Request flow on a cache miss:

- CDN edge: cache miss → forward request to origin.

- Origin service: compute cache key → check Redis (L1 cache) for existence flag.

- If Redis hit: redirect to S3 URL (already generated).

- If Redis miss: check S3 for existing file at `/thumbnails/{cache_key}.{format}`.

- If S3 miss: download source image from S3, process (resize + format convert), upload result to S3, set Redis existence flag with long TTL.

- Return generated image with long-lived cache headers.

Image processing uses libvips (Node.js: Sharp, Python: pyvips) — significantly faster than PIL/Pillow for resize operations due to streaming pipeline architecture and demand-driven processing.

## CDN Edge Caching

Generated thumbnails are immutable — a given (source, params) combination always produces the same output. Use content-addressed URLs and set aggressive cache headers:


```
Cache-Control: public, max-age=31536000, immutable
```

One year TTL. The CDN caches the thumbnail at edge for effectively forever. When source images change (user re-uploads), a new source URL is generated (new S3 key with UUID), which produces a new cache key — old thumbnails naturally expire.

## Security: Signed URLs

An unsigned thumbnail service is vulnerable to abuse: hotlinking (embedding your service's URLs in external sites), scraping (systematic generation of all permutations), and resource exhaustion. Protect with signed URLs:


```
/thumbnail?url=...&w=300&h=200&fit=cover&format=webp&sig=HMAC(secret, params)
```

The service validates the HMAC signature before processing. Signatures can be scoped to a specific domain, user session, or expiry time. For public content, use a shared secret; for user-uploaded private content, sign per-request on the server side.

## Lazy vs Eager Generation

- **Lazy (on-demand):** generate thumbnails only when first requested. Lower storage cost (only generate what's actually needed), but first-request latency is high. Good for long-tail content.

- **Eager (pre-generate):** generate all standard thumbnails immediately after upload. Zero first-request latency, but wastes compute and storage on content that may never be viewed. Good for high-traffic content (product images, featured articles).

Hybrid: eager generation for a small set of canonical sizes (e.g., 300x200 cover WebP) at upload time; lazy generation for all other size/format combinations.

## Resource Limits

- **Max source image size:** reject source images above a limit (e.g., 50MB, 10000×10000 pixels) to prevent memory exhaustion during decode.

- **Max output dimensions:** cap w and h at a maximum (e.g., 4000px) regardless of requested values.

- **Concurrency limits:** image processing is CPU-intensive; limit concurrent generation jobs per pod/instance and queue excess requests.

## Summary

- URL-parameter API with whitelisted dimension values to prevent DoS.

- Deterministic cache key via SHA256 of normalized parameters.

- Generation pipeline: CDN miss → Redis check → S3 check → libvips process → S3 store.

- WebP/AVIF for 30–50% size reduction; JPEG fallback for old browsers.

- Immutable CDN cache with 1-year TTL and content-addressed URLs.

- HMAC-signed URLs to prevent hotlinking and abuse.

- Hybrid eager/lazy generation; resource limits on source and output dimensions.

See also: [Netflix Interview Guide 2026: Streaming Architecture, Recommendation Systems, and Engineering Excellence](https://www.techinterview.org/post/3233460274/netflix-interview-guide-2026-streaming-architecture-recommendation-systems-and-engineering-excellence/)

See also: [Scale AI Interview Guide 2026: Data Infrastructure, RLHF Pipelines, and ML Engineering](https://www.techinterview.org/post/3233460275/scale-ai-interview-guide-2026-data-infrastructure-rlhf-pipelines-and-ml-engineering/)

See also: [Meta Interview Guide 2026: Facebook, Instagram, WhatsApp Engineering](https://www.techinterview.org/post/3233460272/meta-interview-guide-2026-facebook-instagram-whatsapp-engineering/)
