> ## Documentation Index
> Fetch the complete documentation index at: https://notes.kodekloud.com/llms.txt
> Use this file to discover all available pages before exploring further.

# URL Shortener Redirects Bottlenecks and the Wrap Up

> Discusses URL shortener design trade-offs focusing on 301 versus 302 redirects, caching impacts, failures, scaling, and short code generation.

When designing a URL shortener, an early and important decision is how your service tells the browser to go to the long URL. The two common HTTP redirect status codes are:

* 301 Moved Permanently — indicates the resource has moved permanently.
* 302 Found — typically used for temporary redirects.

Most engineers instinctively pick 301 because the mapping "feels" permanent. However, the practical differences matter for analytics, control, and caching behavior.

Redirect behavior at a glance

| Status | Typical cache behavior | When to use |
| - | - | - |
| `301 Moved Permanently` | Often cached by browsers and intermediaries (CDNs, proxies). Future clicks may bypass your service. | Use when the target truly will never change and you want minimal server load. |
| `302 Found` | Generally treated as non-permanent; clicks are more likely to flow through your service. Cache behavior can still vary; control with headers. | Use when you need per-click analytics, the ability to disable or change the destination, or retain control. |
| `307 / 308` | Respect HTTP method semantics (temporary/permanent variants). | Use when preserving request method (POST vs GET) matters. |

Key consequences of choosing 301 vs 302

* 301 reduces server load and latency because browsers/intermediaries can cache the redirect and skip your service on subsequent clicks.
* 301 sacrifices visibility and control: analytics become unreliable because clicks may never reach your servers, and you may not be able to disable or change a short link once caches probe it.
* 302 keeps each click flowing through your service (better analytics, ability to disable links), but increases your server load and latency.
* Cache behavior is not guaranteed — control caching explicitly with response headers such as `Cache-Control`, `Expires`, and `Pragma` when required.

<Frame>
  <img src="https://mintcdn.com/kodekloud-c4ac6d9a/FNsK4qjOEH3p_rqy/images/System-Design-for-Interview-Prep/Warm-Ups-The-Read-Heavy-Classics/URL-Shortener-Redirects-Bottlenecks-and-the-Wrap-Up/url-redirect-301-302-diagram.jpg?fit=max&auto=format&n=FNsK4qjOEH3p_rqy&q=85&s=dfe99eb491b91ded661c86d7a4444a4d" alt="A dark-themed diagram illustrating a URL redirection flow: a user clicks a short link in a browser (left), the request passes through servers showing 301/302 status codes (center), and lands on the full destination webpage preview (right)." width="1920" height="1080" data-path="images/System-Design-for-Interview-Prep/Warm-Ups-The-Read-Heavy-Classics/URL-Shortener-Redirects-Bottlenecks-and-the-Wrap-Up/url-redirect-301-302-diagram.jpg" />
</Frame>

Practical example — a non-cached temporary redirect

```http theme={null}
HTTP/1.1 302 Found
Location: https://example.com/destination
Cache-Control: no-store
```

This preserves per-click visibility and allows you to disable or change the destination later. If you must prevent intermediaries from caching the redirect, customize cache headers accordingly.

Call this trade-off out loud in interviews: if the business requires analytics or the ability to turn a link off later, choose a temporary redirect (302) and explicitly prevent caching. If the product’s priority is absolute performance and the mapping truly never changes, a 301 may be acceptable — but explain the trade-offs.

Next: analyze bottlenecks and failure modes

Before finishing a design, ask two questions about your system:

1. Which component will break first?
2. What can we afford to lose when components fail?

Common considerations for a URL shortener

* Caching layer (e.g., Redis): speeds up reads dramatically. If the cache fails, reads fall back to the primary database and latency increases but correctness remains intact — the database is the source of truth. Explicitly note that the cache is a performance optimization, not durable storage.
* Mapping table durability: the mapping (short\_code → long\_url) is critical data. Losing rows means broken links and irrecoverable user impact.
* Counters/ID generators: any global counter used to create unique short codes must be monotonic and never produce duplicates after a crash. Duplicate codes would assign the same short URL to multiple destinations and break correctness.

Component failure implications

| Component | Failure mode | User-visible impact | Recovery/mitigation |
| - | - | - | - |
| Cache (Redis) | Crash or restart | Higher latency, increased DB load | Failover to DB, warm cache on reads |
| Primary DB (Postgres) | Data loss, corruption | Links lost — user-visible broken URLs | Replication, backups, point-in-time recovery |
| ID generator / counter | Repeat or skip values | Duplicate short codes or gaps | Use durable monotonic counters, coordinate with DB transactions |
| CDN / edge caches | Stale cached redirects | Users redirected to old targets | Use cache-control headers, invalidate caches |

Summary of end-to-end behavior (what to say in an interview)

* A user clicks a short link and the request hits our servers.
* Most requests should be served from cache to reduce latency; however, use `302` (or other non-permanent redirects) if you need per-click analytics and the ability to disable links later.
* The mapping table (short\_code → long\_url) is stored in a durable database (e.g., Postgres) with replicas and regular backups; it is the source of truth.
* Short codes are typically generated using a global counter plus Base62 encoding, or via hashing with deterministic collision handling. Ensure counters cannot repeat.
* Because the workload is read-heavy, scale reads with caching; writes are less frequent and therefore less of a scaling concern.

<Callout icon="lightbulb" color="#1CB2FE">
  If per-click analytics or the ability to disable links after creation is required, prefer a temporary redirect (302) and prevent caching via headers (for example, `Cache-Control: no-store`). Choose `301` only when mappings truly will not change and absolute performance is prioritized.
</Callout>

Key technical takeaways

* URL shorteners are typically read-heavy: caching is the main scaling lever.
* The mapping table is the durable source of truth; protect it with replication and backups.
* Generate unique short codes with a durable monotonic generator (global counter) combined with Base62 encoding; handle collisions if using hashes.
* Use `302` when visibility and control are required; use `301` only when immutability and performance outweigh the need for analytics or revocation.

Example mapping table (conceptual)

```sql theme={null}
-- urls table (conceptual)
short_code    | long_url
------------- | -----------------------------
aX9dQ2z       | https://example.com/course/overview
b7Kp1Rz       | https://example.com/blog/post-title
Qm4xT8w       | https://example.com/pricing/
hT2vN9c       | https://example.com/labs/example-lab
```

Further reading and references

* HTTP Status Codes: [https://developer.mozilla.org/en-US/docs/Web/HTTP/Status](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status)
* Caching best practices: [https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching](https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching)
* PostgreSQL replication and backups: [https://www.postgresql.org/docs/current/high-availability.html](https://www.postgresql.org/docs/current/high-availability.html)

Remember: caching optimizes performance but is not the source of truth. Prefer 302 (with proper headers) when you need analytics and the ability to disable or change short links; use 301 only when the mapping is guaranteed immutable and minimizing server load is the top priority.

<CardGroup>
  <Card title="Watch Video" icon="video" cta="Learn more" href="https://learn.kodekloud.com/user/courses/system-design-for-interview-prep/module/bf4e82c2-1292-42c6-b85f-8b6a0dad559f/lesson/1bdcf4c6-cdeb-4454-8d23-8a1494719d06" />
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.