Compile Ready
All system design questions
System Design/Foundations

URL Shortener

Design a TinyURL-style service that maps billions of long URLs to short, unique, low-latency redirects.

Beginner 45m interview 20m read Very High frequency Popularity 98
Amazon Microsoft Google Uber

Problem Statement

Design a URL Shortener like TinyURL or bit.ly. The service accepts a long URL and returns a compact, unique short code. When a user visits the short link, the service must redirect them to the original long URL with very low latency.

At interview scale, assume billions of stored URLs, a globally distributed user base, and a strongly read-heavy workload. The core challenge is not the CRUD API itself; it is generating collision-free keys, serving redirects fast enough that users do not notice the hop, keeping redirects available during failures, and supporting analytics without slowing the redirect path.

The default design should optimize for low-latency reads, durable URL mappings, and operational simplicity. Optional features such as custom aliases, expiration, user accounts, and click analytics should be layered on without weakening the redirect critical path.

Business use case

Short links are useful whenever the original URL is too long, ugly, or hard to share. They make links fit into SMS, push notifications, social posts, ads, printed material, and QR codes.

Businesses also use shorteners as an attribution layer. A single campaign can generate different short links per channel, region, or experiment and then measure clicks, referrers, devices, and conversion funnels. For consumer products, short links improve sharing and make deep links easier to distribute across apps.

Functional Requirements

  • Shorten a valid long URL and return a unique short URL.

  • Redirect a request for a short code to the original long URL.

  • Support optional custom aliases when the requested alias is available.

  • Support optional expiration or TTL so links can stop resolving after a deadline.

  • Support optional authenticated user accounts to list, delete, and manage links.

  • Collect optional click analytics such as timestamp, referrer, geography, user agent, and device class.

  • Allow deletion or disabling of a short link by its owner or by abuse operations.

Non-Functional Requirements

Latency

Redirects are in the user-facing navigation path, so the target is under 50ms p99 inside a region excluding client network time. Shortening can be slower because it is a write path, but should still complete in under 200ms p99.

Availability

Redirects must remain available even when analytics, user dashboards, or key generation have degraded. A practical target is 99.99 percent or higher for redirects because a broken short link is visible to every downstream user.

Read-heavy scalability

Assume a read to write ratio around 100:1. The architecture should scale the read path independently through CDN caching where safe, Redis or Memcached, read replicas, and a horizontally partitioned key-value store.

Durability

Once a short URL is issued, losing the mapping breaks external links. Store mappings in a durable replicated database, use backups, and avoid acknowledging creates before the mapping is persisted.

Uniqueness

Every short code must map to at most one active long URL. Generated codes need collision avoidance or collision detection, and custom aliases need atomic conditional insert semantics.

Consistency

Create and delete operations need read-after-write behavior for the owner and for immediate redirects. Global propagation can be eventually consistent if regional routing and cache invalidation are handled carefully.

Cost efficiency

The system stores small records but serves many reads. Keep hot mappings in memory, keep analytics asynchronous, and avoid expensive cross-region synchronous writes on every redirect.

Capacity Estimation

Assumptions

Assume 100M new short URLs per month, a 100:1 redirect to create ratio, 30 days per month, a five-year retention window, an average URL mapping record of 500 bytes, and a peak traffic multiplier of 10x over average.

The 500-byte record includes the short code, long URL pointer or normalized long URL, timestamps, owner metadata, TTL, status flags, and small counters. Large analytics events are stored separately.

New URLs

100M per month

3.33M per day

Average write QPS

39 writes per second

100M divided by 30 days divided by 86,400 seconds

Peak write QPS

390 writes per second

10x average peak

Average redirect QPS

3,900 reads per second

100 reads per write

Peak redirect QPS

39,000 reads per second

10x average peak

Five-year URL records

6B mappings

100M per month for 60 months

Primary storage

3 TB raw

6B records times 500 bytes before replication and indexes

Replicated storage

10 to 12 TB

3x replication plus indexes, metadata, and compaction overhead

Average redirect bandwidth

2 MB per second outbound

3,900 redirects per second times roughly 500 bytes of HTTP response headers

Hot cache memory

20 to 30 GB

80 percent of monthly reads served by the hottest 20M records with Redis overhead

Calculations

  • Writes: 100M URLs per month divided by 30 days is 3.33M writes per day. 3.33M divided by 86,400 seconds is about 38.6 writes per second, rounded to 39.
  • Reads: with a 100:1 read to write ratio, average redirect traffic is 3,860 reads per second, rounded to 3,900.
  • Peak: using a 10x traffic multiplier gives about 390 write QPS and 39,000 redirect QPS.
  • Records: 100M per month for 60 months is 6B URL mappings.
  • Storage: 6B records times 500 bytes is 3,000,000,000,000 bytes, about 3 TB raw. With 3 replicas, indexes, tombstones, and compaction headroom, plan for 10 to 12 TB.
  • Bandwidth: redirect responses are mostly headers. 3,900 redirects per second times about 500 bytes is about 1.95 MB per second average. Peak is about 19.5 MB per second before TLS and network overhead.
  • Cache: the 80/20 rule says 20 percent of URLs may drive 80 percent of reads. If the active monthly set is 100M URLs, caching 20M hot mappings at 500 bytes is 10 GB raw. Redis object overhead and fragmentation often double or triple that, so reserve 20 to 30 GB per fully replicated hot cache tier.
  • Keyspace: 6 base62 characters provide 62 to the power of 6, or about 56.8B codes. That covers 6B mappings but leaves less room for reserved, expired, and custom aliases. 7 base62 characters provide about 3.5T codes and are safer.

API Design

POST/api/v1/shorten

Creates a new short URL. The caller may be anonymous or authenticated. The alias and expiration fields are optional; if alias is omitted the service allocates a generated base62 code.

Request


{
  "longUrl": "https://www.example.com/products/very-long-campaign-url",
  "customAlias": "summer-sale",
  "expiresAt": "2027-01-01T00:00:00Z",
  "userId": "user_123"
}

Response


{
  "shortCode": "summer-sale",
  "shortUrl": "https://sho.rt/summer-sale",
  "longUrl": "https://www.example.com/products/very-long-campaign-url",
  "createdAt": "2026-07-26T01:11:28Z",
  "expiresAt": "2027-01-01T00:00:00Z"
}
  • 201Created
  • 400Invalid URL, alias, or expiration
  • 401Authentication required for account-only features
  • 409Custom alias already exists
  • 429Rate limit exceeded
GET/{shortCode}

Resolves a short code and returns an HTTP redirect. The default is 302 Found because it preserves the ability to count future clicks and change policy decisions.

Response


HTTP/1.1 302 Found
Location: https://www.example.com/products/very-long-campaign-url
Cache-Control: no-store
  • 302Redirect to the long URL
  • 301Optional permanent redirect for immutable links without analytics needs
  • 404Unknown short code
  • 410Expired or deleted short code
  • 429Abusive client throttled
DELETE/api/v1/short-urls/{shortCode}

Disables a short URL owned by the authenticated user. The record is usually soft-deleted so old analytics and abuse evidence are retained.

Response


{
  "shortCode": "summer-sale",
  "status": "disabled"
}
  • 200Disabled
  • 401Authentication required
  • 403Caller does not own the link
  • 404Short code not found
GET/api/v1/short-urls/{shortCode}/analytics

Returns aggregate click analytics for an owned short URL. This endpoint reads from the analytics store, not from the redirect serving store.

Response


{
  "shortCode": "summer-sale",
  "totalClicks": 912345,
  "uniqueVisitorsEstimate": 534210,
  "topReferrers": ["search", "social", "email"],
  "dailyClicks": [
    { "date": "2026-07-25", "clicks": 31240 }
  ]
}
  • 200Analytics returned
  • 401Authentication required
  • 403Caller does not own the link
  • 404Short code not found

Keep the redirect endpoint simple and cache-friendly. Authentication, ownership checks, and analytics queries belong on management APIs, not on the anonymous redirect path. For analytics correctness, the redirect service should emit an asynchronous event after it has resolved the mapping.

Database Design

The serving store is keyed by short_code because redirects arrive with only that value. The URL mapping record should be small and self-contained so one point lookup can produce a redirect decision.

For a relational starter design, use a urls table and a users table. At large scale, the same logical schema maps naturally to a distributed key-value store.

urls
short_codevarchar(12)Primary key; generated base62 code or validated custom alias
long_urltextOriginal normalized URL or pointer to compressed overflow storage
created_attimestampCreation time used for retention and auditing
expires_attimestamp nullableNull means no explicit expiration
user_iduuid nullableOwner for authenticated links
click_countbigintApproximate or asynchronously updated aggregate counter
statusvarchar(20)Active, disabled, expired, or flagged
created_regionvarchar(32)Region that accepted the write
users
user_iduuidPrimary key
emailvarchar(320)Unique login identity
created_attimestampAccount creation time
planvarchar(32)Free, paid, enterprise, or internal
statusvarchar(20)Active, suspended, or deleted
click_events_daily
short_codevarchar(12)Partition key for analytics aggregation
event_datedateDaily bucket
clicksbigintAggregated click count
unique_visitors_estimatebigintApproximate cardinality from sketches
top_referrersjsonSmall aggregate, not raw events

Indexes

  • urls.short_code is the primary key and must support single-row point lookup.
  • urls.user_id, created_at supports user dashboards and link history.
  • urls.expires_at supports background expiration sweeps or database TTL policies.
  • users.email is unique for login.
  • Avoid a secondary index on long_url for the redirect path. Deduplication by long URL is optional and often not worth the write amplification.

Relationships

Each URL may belong to one user, but anonymous links have no user. Analytics aggregates reference short_code and can be rebuilt from raw events if necessary. The redirect service should not join across tables during a redirect.

NoSQL alternatives

A distributed key-value database such as DynamoDB, Cassandra, Bigtable, or FoundationDB fits the serving path well. Use short_code as the partition key, store the full redirect record as the value, and make reads single-partition lookups.

The design needs conditional writes for custom aliases and generated key claims. DynamoDB conditional put, Cassandra lightweight transaction for rare alias creation, or a separate key allocation service can enforce uniqueness. Analytics belongs in a write-optimized event pipeline and OLAP store, not in the primary redirect KV table.

High-Level Architecture

Drag to pan · Ctrl/⌘ + scroll to zoom

The redirect critical path is client to edge to load balancer to redirect service to cache or KV store, then back as an HTTP redirect. Key generation and analytics are intentionally off the hot path.

The URL Shortener has two different workloads. The create path is write-oriented, validates URLs, checks abuse signals, allocates a short code, and persists the mapping. The redirect path is read-oriented and must be as close to a single cache or key-value lookup as possible.

CDN and edge infrastructure terminate TLS and can cache safe negative responses or immutable redirects for links that do not require analytics. A regional load balancer routes to stateless API and redirect service instances. Redis stores hot mappings, while the durable KV store remains the source of truth. A key generation worker keeps a pool of unused base62 codes ready so create requests do not need to coordinate on a global counter. Analytics events are emitted asynchronously to a queue and aggregated separately.

Request Flow

  1. 1

    Shorten request arrives

    The client calls POST /api/v1/shorten with a long URL, optional custom alias, optional expiration, and optional user identity. The API service authenticates if needed, normalizes the URL, validates scheme and length, and applies per-user and per-IP rate limits.

  2. 2

    Abuse and policy checks run

    The service checks deny lists, malware reputation, suspicious domains, and policy rules. High-risk URLs can be rejected synchronously; uncertain cases can be accepted in a pending or limited state until asynchronous scanning completes.

  3. 3

    Short code is allocated

    For generated links, the API service obtains a pre-generated code from the Key Generation Service. For custom aliases, it attempts an atomic conditional insert with the requested alias. If the alias already exists, the request returns 409 Conflict.

  4. 4

    Mapping is persisted and cached

    The service writes the mapping to the durable URL store before acknowledging success. It then warms Redis with the new mapping and TTL. The response returns the short URL and metadata.

  5. 5

    Redirect request checks cache

    A browser requests GET /{shortCode}. After edge and load balancer routing, the redirect service looks up the code in Redis. On a cache hit, it can produce the redirect without querying the database.

  6. 6

    Cache miss loads from store

    If Redis misses, the service performs a single key lookup in the URL store using short_code. Active, unexpired mappings are placed back into cache. Missing links can be negative-cached briefly to protect the database from repeated invalid-code traffic.

  7. 7

    Redirect response is returned

    The service returns 302 Found with the long URL in the Location header. Expired or disabled links return 410 Gone. Unknown links return 404 Not Found. The redirect decision should not wait for analytics writes.

  8. 8

    Analytics event is emitted asynchronously

    After resolving the mapping, the redirect service publishes a click event containing short code, timestamp, coarse IP-derived geography, referrer, and user agent. Consumers aggregate counts and sketches in the analytics store.

Core Components

Redirect Service

Serves the hot path for short-code resolution.

This stateless service validates the short code, reads Redis, falls back to the URL store, enforces expiration and disabled status, returns the HTTP redirect, and emits click events asynchronously. Its dependencies should have short timeouts and graceful degradation.

Key Generation Service

Produces unique short codes without per-request global coordination.

The service pre-generates base62 codes, keeps an unused key pool, atomically claims keys for create requests, and records used keys. It can allocate ranges to workers so create throughput scales horizontally while preserving uniqueness.

Hot Mapping Cache

Absorbs the majority of redirect lookups.

Redis or Memcached stores short_code to redirect record mappings with TTL aligned to link expiration. It should support high QPS, low p99 latency, request coalescing on misses, and negative caching for invalid codes.

Primary URL Store

Durable source of truth for all mappings.

A key-value store persists the mapping and supports conditional writes. It is partitioned by short code, replicated for availability, backed up for durability, and sized for billions of small records.

Analytics Pipeline

Captures click events without slowing redirects.

Kafka, Kinesis, Pub/Sub, or a similar queue receives best-effort click events. Consumers deduplicate where possible, aggregate by time bucket and dimension, and store results in an OLAP database or time-series store.

Load Balancer

Spreads traffic across stateless services and regions.

The load balancer performs health checks, routes traffic to healthy redirect service instances, and can separate create API traffic from redirect traffic if the workload requires different scaling policies.

Abuse and Safety Scanner

Prevents the shortener from becoming a phishing amplifier.

The scanner evaluates long URLs against malware feeds, phishing signals, domain reputation, and customer policy. It can block creation, mark links for interstitial warnings, or disable previously created links.

Deep Dive

Key generation strategies

There are three common approaches, and a strong answer compares them explicitly.

Counter plus base62: maintain a monotonically increasing integer and encode it using characters 0-9, a-z, and A-Z. It is compact, deterministic, and collision-free if the counter is serialized correctly. The downside is coordination. A single counter becomes a bottleneck, while distributed counters need range allocation, Snowflake-style IDs, or database sequences. Sequential codes are also enumerable, so attackers can scan links unless rate limiting and randomization are added.

Hash long URL: compute MD5, SHA-256, or another hash of the long URL and take the first N base62 characters. This avoids a central counter, but collisions are possible because the output is truncated. The system must check whether the candidate code already exists and retry with a salt, longer prefix, or random suffix. Hashing also makes duplicate long URLs produce the same short code unless user identity or salt is included, which may or may not be desirable.

Pre-generated Key Generation Service: generate random or sequential base62 codes offline and store them in two logical databases: unused_keys and used_keys. Create requests atomically move a code from unused to used and then write the URL mapping. This keeps code allocation fast, avoids collisions on the request path, and allows workers to prefetch batches. The tradeoff is operational complexity: the unused pool must be replenished, allocation must be idempotent, and lost prefetched batches need recovery.

For this question, the KGS or range-allocated counter approach is usually the cleanest interview answer because it gives uniqueness without repeated collision checks at high scale.

301 versus 302 redirects

301 Moved Permanently tells clients and search engines that the redirect is permanent. Browsers and intermediate caches may cache it aggressively. This reduces load and latency, but it can bypass the service on later visits, which weakens click analytics, abuse takedowns, and destination changes.

302 Found or 307 Temporary Redirect keeps clients coming back to the shortener each time. That costs more serving capacity, but it preserves analytics accuracy, lets the service enforce expiration, and allows links to be disabled quickly. Most interview designs choose 302 by default.

A mature product can support both. For user-owned campaign links with analytics, use 302 and Cache-Control: no-store. For internal immutable links with no analytics requirements, 301 plus edge caching can reduce cost.

Cache strategy and hit ratio

The cache should store the full redirect decision, not just the long URL. Include long URL, expiration, status, owner policy flags, and redirect type so the service does not need a database read on a hit.

Use read-through caching on misses and write-through or cache warming on creates. TTL should be the minimum of a default cache TTL and the link expiration time. Negative-cache unknown short codes for a short period such as 30 to 120 seconds to protect the database from random scans.

The 80/20 assumption is powerful here: if 20 percent of active links drive 80 percent of redirects, a modest Redis fleet can remove most database traffic. Track cache hit ratio, p99 cache latency, miss amplification, hot-key skew, and eviction rate. For celebrity or viral links, replicate hot keys across cache shards or use local in-process caching to avoid one shard becoming overloaded.

Custom aliases and collision handling

Custom aliases are user-visible and must be treated differently from generated keys. Validate length, allowed characters, reserved words, impersonation risk, trademarks for enterprise customers, and case sensitivity. A good default is case-sensitive generated codes but case-insensitive custom aliases only if the product explicitly wants that behavior.

The database operation must be atomic: insert the alias only if short_code does not already exist. Never check then insert in two separate steps because concurrent requests can both pass the check. If an alias is taken, return 409 Conflict and let the caller choose another.

Generated-code collisions should be invisible to users. With a KGS, collisions are prevented before allocation. With hash or random generation, the create service retries with a salt or longer code after a conditional insert fails. Put a small retry bound and surface a 500 only if the keyspace or generator is unhealthy.

Database choice for the serving path

A relational database is acceptable for a small single-region prototype, but the production serving path is a key-value workload: lookup by short code and return one record. That favors DynamoDB, Cassandra, Bigtable, or another horizontally scalable KV store.

Partition by short_code. Base62 codes generated sequentially can create hot partitions if the partitioner preserves prefix order, so use a database with hash partitioning or randomize prefixes. Replicate data across availability zones, use quorum or leader-based writes depending on the store, and keep redirect reads local to the serving region whenever possible.

Secondary indexes should not be needed for redirects. User dashboards and analytics can use separate tables optimized for user_id and time. This separation keeps the redirect store small, predictable, and highly available.

Analytics without hurting redirects

Counting clicks synchronously in the urls row is a common beginner mistake. A viral link could turn one row into a write hotspot, and the redirect would depend on the analytics store.

Instead, the redirect service emits an event after resolving the URL. The event pipeline can batch, sample if product allows it, and aggregate by short code and time window. For unique visitors, use approximate sketches such as HyperLogLog rather than storing every visitor in the serving database.

If analytics delivery fails, redirects should continue. The system can buffer locally for a short time, drop non-critical events under pressure, or write to a durable queue with backpressure, but it should not turn analytics degradation into redirect downtime.

Scaling

Prototype: single region and relational database

Start with one stateless API service, one relational database table keyed by short code, and simple random or counter-based code generation. Add a small Redis cache when redirect traffic grows. This is enough to demonstrate correctness, custom alias conflict handling, and expiration.

Growth: cache and read replicas

Separate create and redirect endpoints behind the load balancer. Add Redis read-through caching for hot mappings, database read replicas if using relational storage, and asynchronous analytics via a queue. Keep the redirect service stateless so horizontal scaling is straightforward.

Large scale: sharded replicated key-value store

Move the URL mapping table to a distributed KV store partitioned by short code. Introduce a Key Generation Service with pre-generated pools or range allocation. Replicate across availability zones, add circuit breakers, and use negative caching to absorb invalid-code scans.

Global scale: multi-region redirects

Route users to the nearest healthy region using geo-DNS or anycast. Replicate mappings globally through asynchronous streams or multi-region database replication. Keep reads local, make creates strongly durable in a home region, and propagate cache invalidations for deletes and abuse takedowns.

Extreme scale: edge decisions and specialized analytics

For immutable non-analytics links, push redirect mappings to edge caches. For analytics links, keep 302 at the service but use regional queues and OLAP stores. Add hot-key replication, adaptive rate limiting, abuse automation, and capacity isolation for enterprise tenants.

Bottlenecks & Optimizations

Single key generator bottleneck

Do not coordinate every create request through one database sequence. Allocate ranges to workers, pre-generate keys in batches, or use a KGS with an unused key pool. Monitor pool depth and generation lag.

Database overload from cache misses

Use Redis read-through caching, cache warming on create, negative caching for misses, request coalescing, and hot-key replication. Keep database lookups as single-partition reads by short code.

Viral link hot spot

A single celebrity link can dominate traffic. Replicate that mapping across cache shards, add local in-process caching, and consider CDN edge caching if analytics accuracy can tolerate sampled or delayed counts.

Synchronous analytics writes

Emit click events to a queue and aggregate asynchronously. Never update the URL row on every redirect. If exact counters are required, batch increments by short code and time bucket.

Large or malicious long URLs

Set maximum URL length, normalize inputs, reject unsupported schemes, scan domains, and store very long metadata outside the hot serving record if necessary. Keep the redirect record bounded in size.

Cross-region consistency delays

Use a home-region write model with fast replication, route immediate post-create redirects to the write region when needed, and invalidate or update regional caches after deletes, expirations, and abuse actions.

Failure Handling

Cache outage

Redirect services fall back to the primary URL store with strict timeouts and rate limits to avoid a database stampede. Use circuit breakers, partial cache fleet isolation, and gradual cache warmup after recovery.

Primary database partition or regional failure

Serve reads from replicas when possible and fail over regional traffic to a healthy region. For creates, either pause new link creation briefly or route to another write-capable region. Redirect availability should be prioritized over management features.

Key pool exhaustion

Alert before the unused pool reaches a low watermark. KGS workers should replenish in batches, and the create API should degrade gracefully with retryable errors rather than issuing duplicate codes.

Analytics queue unavailable

Continue redirects. Buffer events locally for a bounded time if safe, drop low-priority analytics under pressure, and expose freshness indicators in dashboards. Do not block the redirect on analytics recovery.

Abuse scanner degraded

Apply a conservative policy for anonymous or high-risk creates, such as lower rate limits or pending status. Trusted enterprise traffic can continue with delayed scanning, while known-bad domains remain blocked from cached deny lists.

Bad deployment corrupts redirect decisions

Use canary deployments, fast rollback, synthetic redirect probes, and shadow reads comparing cache and database records. Keep a kill switch that disables risky features such as destination rewriting without taking down redirects.

Security

Malicious URL scanning

Shorteners are frequently abused for phishing and malware. Scan long URLs at creation, rescan popular links periodically, integrate domain reputation feeds, and support warning interstitials or takedowns.

Rate limiting

Apply per-IP, per-user, per-token, and per-domain limits on create requests. Also throttle random-code scans on redirects to protect cache and database capacity from enumeration attacks.

Open-redirect protection

The product is intentionally a redirector, but it must prevent dangerous schemes and ambiguous parsing. Accept only safe schemes such as HTTP and HTTPS, normalize URLs with a trusted parser, and block internal network targets if the service later fetches metadata.

Enumeration resistance

Sequential short codes are easy to crawl. Randomize generated codes, use sufficiently long base62 strings, monitor scan patterns, and rate-limit 404-heavy clients.

Access control

Only owners or privileged operators can delete links, view detailed analytics, or edit metadata. Anonymous redirects should not reveal private owner data.

Privacy and analytics minimization

Click analytics can include personal data. Store coarse geography instead of raw IP where possible, apply retention windows, honor deletion requests, and separate raw events from public dashboards.

Tradeoffs

Pros

  • +Simple redirect data model with a single primary lookup key.
  • +Read-heavy workload scales well with cache and KV storage.
  • +Asynchronous analytics keeps the user-facing path fast.
  • +Pre-generated keys provide collision-free creation with predictable latency.
  • +302 redirects preserve observability and takedown control.

Cons

  • 302 redirects cost more infrastructure than permanent edge-cached redirects.
  • Custom aliases add contention, abuse risk, and support complexity.
  • Multi-region deletes and abuse takedowns require careful cache invalidation.
  • Exact analytics can conflict with low-latency redirects.
  • Sequential key generation can leak volume and enable enumeration if not mitigated.

Alternatives

Alternative one is a pure hash-based system: hash the long URL, truncate, and retry on collision. It is easy to build but collision handling and duplicate semantics become tricky.

Alternative two is a database sequence with base62 encoding. It is clean for a single region but needs range allocation or sharded sequences at scale.

Alternative three is edge-only redirect hosting for immutable links. It is extremely fast and cheap for static mappings, but weak for analytics, expiration, and abuse response.

When not to use this design

Do not use a public URL shortener for sensitive access-control decisions. Anyone with the short link can usually access the destination. If the problem requires private sharing, signed URLs, authorization checks, or expiring secrets, design an access-controlled sharing system rather than a simple shortener.

Follow-up Questions

How many characters should the short code have?

Compute the keyspace. Base62 with 6 characters gives about 56.8B combinations, while 7 characters gives about 3.5T. For 6B five-year mappings, 6 characters is mathematically enough but operationally tight once you include reserved words, expired links, custom aliases, and collision margin. Choose 7 by default.

Should the same long URL always return the same short code?

Usually no. Different users and campaigns may need separate analytics and expiration policies for the same destination. If deduplication is desired for anonymous links, it should be a product decision and not required for the redirect serving path.

How do you delete or expire a link safely?

Use a status field and expires_at in the serving record. On redirect, return 410 Gone for expired or disabled records. Also evict or update caches when the status changes. A background job can compact expired records later, but correctness should not depend on the sweep running exactly on time.

How do you support links created in one region and immediately read in another?

Options include synchronous multi-region writes, home-region routing for a short read-after-write window, or accepting small propagation delays. For a beginner design, choose durable write in one region plus fast asynchronous replication, then route the creator to the write region for immediate validation.

How do you prevent short-code enumeration?

Use random or non-obvious codes, avoid plain sequential exposure, apply rate limits to 404-heavy clients, detect scan patterns, and consider longer codes for anonymous links. Enumeration is a security and privacy risk because public links may expose sensitive destinations.

Where should click_count be updated?

Not synchronously in the redirect transaction. Emit click events to a queue, aggregate them by short code and time bucket, and periodically update summary tables. The click_count in the URL row can be approximate or eventually consistent.

What happens when Redis has stale data after a delete?

Use cache invalidation on delete, short TTLs for sensitive links, and status checks from the database for high-risk operations. If stale redirects are unacceptable for abuse takedowns, maintain a small deny-list cache that is checked before normal mapping cache results.

Company Variations

Amazon

Amazon interviewers often push on DynamoDB-style partitioning, availability zones, operational alarms, abuse prevention for public endpoints, and cost. Be ready to explain conditional writes for aliases and how the redirect path survives dependency failures.

Microsoft

Microsoft may frame this around enterprise link management, compliance, tenant isolation, Azure Front Door or CDN, and integration with identity. Discuss owner permissions, audit logs, retention, and private organizational short domains.

Google

Google tends to probe global scale, caching layers, tail latency, abuse detection, and data freshness. Expect follow-ups on base62 keyspace, multi-region replication, 301 versus 302 behavior, and high-QPS read serving.

Uber

Uber may tie short links to SMS, deep links, driver and rider notifications, and regional reliability. Emphasize low-latency mobile redirects, observability for campaigns, and graceful degradation during regional incidents.

Interview Tips

Lead with the read-heavy nature of the system. Draw the redirect path first because that is the business-critical path, then add create, key generation, analytics, and abuse controls around it. When tradeoffs appear, tie them to product goals: analytics accuracy favors 302, raw latency favors edge caching, and operational simplicity favors a KV store plus Redis.

What interviewers expect

  • State assumptions and compute writes, reads, storage, bandwidth, and cache size.
  • Separate create path, redirect path, key generation, and analytics.
  • Explain at least two key generation strategies and choose one.
  • Use short_code as the primary lookup key and avoid joins on redirects.
  • Call out 301 versus 302 and its impact on analytics.
  • Discuss availability, cache misses, abuse, and multi-region scaling.

Common mistakes

  • !Updating click_count synchronously on every redirect.
  • !Using a hash without explaining collision detection and retry.
  • !Forgetting custom alias atomicity and race conditions.
  • !Choosing 301 by default while promising accurate click analytics.
  • !Ignoring abuse, phishing, and enumeration risks.
  • !Designing joins or multi-step database reads in the redirect path.

Red flags

  • ×No concrete capacity math or keyspace calculation.
  • ×No cache strategy for a 100:1 read-heavy workload.
  • ×No durable source of truth for issued links.
  • ×No plan for expiration, deletion, or takedown cache invalidation.
  • ×Treating analytics as equally critical as redirects.

Revision Notes

  • Use short_code as the primary key and keep redirects to one cache lookup or one KV lookup.
  • At 100M new URLs per month and 100:1 reads, expect about 39 write QPS average and 3,900 redirect QPS average, with 10x peaks around 390 and 39,000.
  • Five years of mappings is about 6B records and 3 TB raw at 500 bytes each, or roughly 10 to 12 TB replicated with overhead.
  • Base62 length matters: 6 chars gives 56.8B combinations, 7 chars gives about 3.5T.
  • Prefer 302 when analytics, expiration, and takedowns matter. Use 301 only for immutable links where client caching is acceptable.
  • Avoid synchronous analytics writes. Publish click events to a queue and aggregate asynchronously.
  • KGS with unused_keys and used_keys avoids per-request collision checks but adds operational responsibility.
  • Protect the system with URL scanning, rate limiting, alias validation, and enumeration detection.

Flashcards

Quiz

0/7 answered

  1. 1.Which redirect status is the best default when click analytics must remain accurate?

  2. 2.What is the most important lookup key in the redirect serving store?

  3. 3.Given 100M creates per month and 30 days per month, what is the approximate average write QPS?

  4. 4.Why should click analytics be asynchronous?

  5. 5.Which key generation approach best avoids collisions on the request path?

  6. 6.What is the best response for an expired or deliberately disabled short link?

  7. 7.Why can sequential base62 codes be risky?

Cheat Sheet

Goal: map long URLs to short unique codes and redirect in under 50ms p99 within a region.

Workload: 100M creates per month, 100:1 reads, about 39 write QPS average, about 3,900 redirect QPS average, 10x peak.

Storage: 6B records over five years. At 500 bytes each, about 3 TB raw and 10 to 12 TB replicated with overhead.

Key generation: counter plus base62 is simple but needs coordination. Hashing needs collision retries. KGS with unused and used key pools gives predictable collision-free allocation.

Serving path: client to CDN or load balancer to redirect service to Redis. On miss, read URL KV store by short_code, fill cache, return 302.

Database: KV store partitioned by short_code. Conditional writes for custom aliases. Separate analytics and user-dashboard storage from redirect serving.

Caching: cache full redirect records, respect expiration TTL, negative-cache invalid codes briefly, and replicate hot keys.

Redirect choice: 302 for analytics and takedowns. 301 only for immutable links where client caching is acceptable.

Analytics: publish click events asynchronously to a queue; aggregate in OLAP or time-series storage.

Security: scan malicious URLs, block unsafe schemes, rate-limit creation and enumeration, protect analytics with auth, and support takedowns.

References