· SWE Editorial · System Design  · 6 min read

Design a URL Shortener: Architecture Diagram and Data Flow

A layer-by-layer breakdown of how a request actually moves through a URL shortener — CDN, load balancer, app servers, cache, and database — with separate diagrams for the write path and the read path.

A layer-by-layer breakdown of how a request actually moves through a URL shortener — CDN, load balancer, app servers, cache, and database — with separate diagrams for the write path and the read path.

Beyond the Box-and-Arrow Sketch

Most candidates can draw a URL shortener architecture in five boxes. Far fewer can explain, precisely, what happens to a single request as it crosses each layer, or why the write path and read path deliberately diverge. That precision is what a staff-level interviewer is probing for once the high-level shape is on the whiteboard. This article assumes you’ve already nailed down requirements (see the companion interview guide) and goes one layer deeper: the actual data flow, layer by layer.

The Full Layer Stack

 Client (browser/app)


 ┌────────────────┐
 │      CDN       │  ← caches redirects for hot/viral links at the edge
 └───────┬────────┘
         │ (cache miss)

 ┌────────────────┐
 │ Load Balancer   │  ← L7, round-robin or least-connections across app servers
 └───────┬────────┘


 ┌────────────────┐
 │  App Servers    │  ← stateless; handle both /shorten (write) and /{code} (read)
 └───────┬────────┘

   ┌─────┴─────┐
   ▼           ▼
┌──────┐   ┌─────────┐
│Cache │   │Database │
│Redis │   │(KV store│
└──────┘   │ or SQL) │
           └─────────┘

Every layer exists to shed load from the layer below it. The CDN sheds load from the load balancer, the load balancer sheds load from app servers, the cache sheds load from the database. Say this explicitly — it demonstrates you understand caching as a system-wide discipline, not just “add Redis.”

The Write Path: Creating a Short URL

1. Client POST /api/shorten { long_url: "https://..." }
2. Load balancer routes to any available app server (write requests
   are NOT cache-eligible, so this is a straight pass-through)
3. App server:
   a. Validate the long URL (well-formed, not on a blocklist)
   b. Generate a unique short code (base62 counter, see interview guide)
   c. Write { short_code, long_url, created_at, expires_at } to DB
   d. (Optional) Pre-warm the cache with this new mapping
4. App server returns { short_url: "https://sho.rt/aZ9kLp" } to client

Key design decision: the write path talks to the primary database node, never a replica, because you cannot risk a read-your-write inconsistency where a user creates a link and then immediately gets a 404 redirecting it. This is a classic follow-up question — always name the consistency requirement explicitly.

Writes are infrequent relative to reads (per the 100:1 to 1000:1 ratio established in the requirements), so the write path does not need to be nearly as horizontally scaled as the read path — a smaller fleet of write-capable app servers is fine.

The Read Path: Resolving a Short URL

1. Client GET https://sho.rt/aZ9kLp
2. CDN checks edge cache for this path
     HIT  → CDN returns cached 301/302 redirect directly (no origin hit)
     MISS → forward to load balancer
3. Load balancer routes to any app server
4. App server checks Redis cache for short_code -> long_url
     HIT  → return redirect immediately, log click event async
     MISS → query database, populate cache, return redirect
5. Client's browser follows the Location header to long_url

The critical detail: on a cache miss, the app server must populate the cache before returning, using a read-through pattern, so the next request for the same code is a cache hit. Never let the client-facing response wait on analytics writes — click-tracking (covered in the companion data model article) should be fire-and-forget via a message queue or async task, not inline in the redirect’s critical path. A redirect blocked on an analytics DB write is a latency bug waiting to happen.

Cache Invalidation: The Part Everyone Glosses Over

URL shortener mappings are close to immutable — once created, a short_code -> long_url pair almost never changes. This makes caching unusually easy compared to most systems, but there are still three invalidation scenarios worth naming in an interview:

  1. Link expiration. If a link has a TTL, the cache entry must expire at or before the DB record does. Set the Redis TTL equal to (or slightly shorter than) the link’s expiration to avoid serving a dead link from cache.
  2. Manual deletion/deactivation. If a user or admin deletes a link, you must actively invalidate the cache key (DEL short_code) rather than waiting for natural TTL expiry — otherwise the link keeps working from cache after “deletion,” which is a real production bug and a great interview gotcha to raise yourself.
  3. Custom alias collision resolution. If a custom alias is claimed, then released, then reused for a different long URL, a stale cache entry could redirect the new alias to the old destination. Always invalidate on any write to an existing key, not just on creation.

The general rule to state out loud: cache invalidation is driven by the write path, not by a background sweep. Any service that writes to the mapping table owns clearing the corresponding cache key in the same transaction/step.

Read vs. Write Path Side-by-Side

AspectWrite Path (/shorten)Read Path (/{code})
FrequencyLow (1 unit)High (100-1000x)
Target latency~200ms acceptable<100ms, ideally <20ms cached
Talks toDB primary onlyCDN → Cache → DB replica
Scaling leverVertical + modest horizontalAggressive horizontal + edge caching
Consistency needStrong (read-your-write)Eventual is fine
Cache rolePopulate on write (optional)Primary defense layer

Handling Redirect Status Codes Correctly

This deserves its own callout because it trips up even strong candidates. A 301 (Moved Permanently) tells the browser to cache the redirect itself, so subsequent visits never even hit your CDN or servers — great for scale, bad if you ever need to change or expire the destination, and bad for per-click analytics since the browser skips your server entirely after the first hit. A 302 (Found/Temporary) forces the browser to check in every time, giving you accurate click counts and full control, at the cost of every single click hitting your infrastructure. Most production shorteners default to 302 specifically because click analytics is a core product feature, not an afterthought — say this and you’ll sound like someone who has actually operated one of these systems.

Putting It Together

The architecture only makes sense once you see it as two separate flows sharing infrastructure: a small, strongly-consistent write path that touches the primary database, and a massive, cache-first read path that fans out across CDN, edge cache, and application-layer cache before ever touching a database replica. Drawing one combined diagram is fine for the whiteboard, but narrating these as two distinct flows — with distinct scaling levers, distinct consistency requirements, and a clear invalidation rule tied to the write path — is what turns a “draws boxes” answer into a “understands distributed systems” answer.

For 50+ system design deep-dives like this one, see The 0-to-1 SWE Interview Playbook (Amazon: https://www.amazon.com/dp/B0H256Z1MF?tag=sirjohnnymai-20). It includes annotated request-flow diagrams for the URL shortener plus a dozen other classic interview questions.

Pair this article with “Capacity Estimation” to size each of these layers with real numbers, and “Data Model and APIs” for the exact schema and endpoint contracts referenced above.

Back to Blog

Related Posts

View All Posts »

Design a URL Shortener: Capacity Estimation

Back-of-the-envelope math for a URL shortener — QPS, storage growth over five years, bandwidth, and cache sizing using the 80/20 rule. The exact numbers interviewers expect you to produce on a whiteboard.

Design a URL Shortener: Data Model and APIs

The schema, REST API contracts, rate limiting strategy, and SQL-vs-NoSQL decision for a URL shortener — the implementation details interviewers probe once the high-level architecture is settled.