· Software Engineers Editorial · Technical · 6 min read
URL Shortener System Design: Step-by-Step Guide
URL Shortener System Design. Updated June 2026 with verified data.
URL Shortener System Design: Step‑by‑Step Guide
In 2024, the average daily traffic for popular shortening services such as bit.ly and tinyurl.com exceeded 150 million redirects per day—roughly the same number of requests handled by a midsize e‑commerce site during a flash sale. Designing a system that can reliably serve that load while keeping latency under 50 ms is a classic interview problem, but it also mirrors real‑world constraints faced by engineers at scale‑focused firms. This guide walks through the design choices, data‑driven assumptions, and trade‑offs you would need to discuss in a coding interview—or to prototype a production‑ready service today.
1. Define the Core Requirements
| Requirement | Detail |
|---|---|
| Functional | • Generate a unique short URL (e.g., https://sho.rt/abc123).• Resolve the short link to the original long URL. • Optional analytics (click count, referrer, geo). |
| Non‑functional | • Throughput: ≥ 150 M redirects/day (≈ 1 800 QPS) for a modest service. • Latency: ≤ 50 ms 99th‑percentile for redirect. • Availability: 99.9 % uptime (≈ 8.8 h downtime/year). • Scalability: Horizontal scaling to support 10× load spikes. |
| Constraints | • Short URL length ≤ 7 characters (62‑base yields ~ 3.5 B combos). • Avoid collisions without costly coordination. |
The interview focus is usually on high‑read, low‑write workloads, but the design must also accommodate occasional bulk URL creation (e.g., marketing campaigns).
2. Estimate Traffic and Storage
Assume a startup targets 1 M active users who each create 5 short links per month and generate an average of 300 clicks per link in the first week.
- Writes per day: 1 M × 5 ÷ 30 ≈ 166 k INSERTs.
- Reads per day: 1 M × 5 × 300 ≈ 1.5 B LOOKUPs → ~ 17 k QPS.
A production‑grade service like bit.ly sees spikes up to 5× the baseline during viral campaigns, so we provision for ≈ 100 k QPS to stay safe.
Storage: Each mapping stores a short code (7 bytes), long URL (average 150 bytes), creation timestamp (8 bytes), and optional analytics fields (≈ 20 bytes). Roughly 200 bytes per record.
Projected size after 2 years: 1 M × 5 × 2 ≈ 10 M records → ~ 2 GB total. This comfortably fits in modern SSDs, but we still shard for write scalability.
3. Data Model
A simple relational schema works well for the core mapping:
CREATE TABLE url_mapping (
short_code CHAR(7) PRIMARY KEY,
long_url TEXT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
clicks BIGINT DEFAULT 0
);
The short_code column can be a HASH of the long URL (e.g., MurmurHash3) truncated to 7 characters, but to avoid collisions we append a small counter (or use a deterministic base‑62 encoding of an auto‑increment ID).
Analytics can be stored in a separate click_events table or forwarded to an analytics pipeline (Kafka → ClickHouse) to keep the write path fast.
4. High‑Level Architecture
┌─────────────┐ ┌───────────────┐ ┌───────────────┐
│ Client │←→│ API Gateway │←→│ Load Bal. │
└─────────────┘ └───────┬───────┘ └───────┬───────┘
│ │
┌────────▼─────────┐ ┌─────▼───────┐
│ URL Service │ │ Click API │
└───────┬──────────┘ └───────┬──────┘
│ │
┌───────────▼─────────┐ ┌──────▼───────┐
│ Redis / Memcached │ │ PostgreSQL │
└───────────┬─────────┘ └───────┬───────┘
│ │
┌───────▼───────┐ ┌───────▼───────┐
│ Sharded DB │ │ Analytics │
└───────────────┘ └───────────────┘
- API Gateway handles authentication, rate‑limiting, and routing.
- URL Service is the write‑path: validates input, generates the short code, and persists the mapping.
- Redirect Service (served from the same API layer) reads from an in‑memory cache (Redis) to satisfy the 50 ms latency SLA.
- Click API increments counters asynchronously to avoid slowing redirects.
5. Generating Short Codes without Collisions
Two common strategies:
| Strategy | Pros | Cons |
|---|---|---|
| Sequential ID + Base‑62 | Predictable, no collisions, easy shard key. | Exposes growth pattern, easier to scrape. |
| Hash‑Based (e.g., MurmurHash3) + Salt | No central coordination, appears random. | Requires collision detection & retry; extra DB round‑trip. |
For most interview scenarios, the sequential ID approach wins for simplicity: each write obtains an auto‑increment value from a single‑writer database node (or a distributed ID service like Snowflake) and encodes it to base‑62. The resulting code (e.g., abc123) is unique system‑wide.
6. Read Path Optimization
Redirect latency dominates the user experience. A typical flow:
- Client requests
https://sho.rt/abc123. - Edge CDN (Cloudflare, Fastly) forwards to the nearest Load Balancer.
- Load Balancer hits Redis.
- If cache miss, fallback to PostgreSQL (read‑replica).
Cache keys are the short code, values the long URL. A TTL of 24 h plus write‑through invalidation ensures consistency. Empirical data from Twitter’s URL shortener shows > 95 % cache hit rate after the first hour of a link’s creation.
7. Scaling the Write Path
Even though writes are an order of magnitude lower than reads, they must not become a bottleneck. Strategies:
- Sharding by short code prefix (e.g., first two characters) spreads inserts across multiple DB shards.
- Batch insertion for bulk campaign uploads reduces per‑record overhead.
- Async validation (checking for abusive URLs) off‑loads to a background worker queue (e.g., SQS).
8. Cost Analysis (2026 pricing snapshot)
| Component | Monthly Cost (USD) | Assumptions |
|---|---|---|
| 3× t3.medium (API) | $135 | 2 vCPU, 4 GB RAM, 24/7 |
| Redis Cache (elasticache) | $250 | 2 nodes, 7 GB each |
| PostgreSQL (single‑AZ) | $300 | 2 vCPU, 16 GB RAM, 500 GB SSD |
| CDN (2 TB egress) | $180 | 2 TB data transfer |
| Total | ≈ $865 | + 10 % overhead for monitoring |
These numbers reflect Updated June 2026 pricing from major cloud providers. A start‑up can comfortably run the service for under $1 k/month, with headroom to scale to 10× traffic by adding extra API instances and read replicas.
9. Observability
- Metrics: request latency, cache hit ratio, QPS per tier, error rates.
- Tracing: end‑to‑end request IDs propagated via OpenTelemetry to pinpoint slow DB lookups.
- Alerting: P‑99 latency > 70 ms or cache miss rate > 20 % triggers PagerDuty.
In production, a Grafana + Prometheus stack provides the visibility needed to meet the 99.9 % SLA.
10. Failure Modes and Mitigations
| Failure | Impact | Mitigation |
|---|---|---|
| Cache outage | All reads go to DB → latency spikes. | Auto‑fallback to DB; allocate extra read replicas; warm‑up cache on startup. |
| DB shard loss | Loss of newly generated short codes. | Replicate each shard to a standby region; use leader‑follower replication. |
| Hot short code (viral link) | Disproportionate load on a single cache key. | Enable rate‑limiting per key, burst‑able scaling for Redis shards. |
| Abuse (spam, phishing) | Reputation damage. | Real‑time URL safety checks using a third‑party API; blacklist propagation. |
11. Extending the Service
- Custom domains (
mybrand.co/xyz) – store domain → user mapping and route via the same redirect logic. - Expiration – TTL per link; a background job sweeps expired rows.
- A/B testing – route a percentage of clicks to alternative landing pages by storing multiple targets per short code.
These features add modest complexity but follow the same data‑driven principles outlined above.
12. Interview Takeaway
When you present this design in a coding interview, emphasize:
- Quantitative reasoning – traffic, storage, cost.
- Clear trade‑off articulation – why a simple relational DB with a cache beats a NoSQL solution for this workload.
- Scalability mindset – how you would shard, cache, and handle spikes.
A concise, data‑first narrative demonstrates the ability to translate business requirements into concrete engineering decisions—exactly what senior SWE roles at high‑growth companies look for.
For deeper practice on turning system‑design prompts into interview‑ready stories, see 0→1 SWE Interview Playbook.
FAQ
Q1. How do we guarantee uniqueness without a central ID generator?
A common approach is to use a distributed ID service (e.g., Snowflake) that embeds a timestamp, machine ID, and sequence counter. Encoding the 64‑bit ID to base‑62 yields a collision‑free short code.
Q2. Why not store the mapping in a key‑value store like DynamoDB?
Key‑value stores give constant‑time reads, but they lack strong transactional guarantees for the write‑path (e.g., atomic increment of a counter). For a system where writes are low volume, a relational DB provides ACID safety with minimal operational overhead.
Q3. Can we serve redirects directly from the CDN edge without hitting any backend?
Yes, for ultra‑low latency you can push frequently accessed short‑code → long‑URL pairs into the CDN’s edge cache using cache‑purge APIs. However, this introduces cache‑consistency challenges and limits flexibility for analytics. A hybrid approach—edge cache for hot links, backend fallback for the rest—balances performance and observability.