System Design Interview Design a URL Shortener System Design Interview Design a URL Shortener

System Design Interview: Design a URL Shortener

The question “Design a URL shortener” is a classic system design interview problem. It appears simple on the surface but allows interviewers to evaluate a wide range of skills:

  • Requirements gathering
  • API design
  • Database modeling
  • Hashing and encoding techniques
  • Scalability
  • Caching
  • Load balancing
  • Availability and fault tolerance
  • Performance optimization

In this article, we’ll walk through a complete system design interview answer for building a URL shortening service such as TinyURL, Bitly.

By the end of this guide, you’ll know how to structure your response, what tradeoffs to discuss, and how to present a production-ready architecture.


What Is a URL Shortener?

A URL shortener is a service that converts a long URL into a shorter, more manageable link.

For example:

Original URL:

https://www.example.com/products/category/electronics/laptops/gaming-laptop-15-inch-rtx-4070?ref=homepage&campaign=summer_sale

Shortened URL:

https://short.ly/aB3xY9

When a user clicks the shortened link, the system redirects them to the original long URL.


Interviewers like this question because it tests both basic system design concepts and advanced scalability topics.

It allows discussion around:

  • Read-heavy vs write-heavy systems
  • Key-value storage
  • Database indexing
  • Distributed ID generation
  • Caching strategies
  • Redirect mechanisms
  • Rate limiting
  • Analytics
  • High availability
  • Consistency vs availability tradeoffs

A strong answer should not jump directly into implementation. Instead, it should begin with requirements clarification.


Step 1: Clarify Requirements

In any system design interview, always start by clarifying the scope.

You can ask questions like:

  • What features should the URL shortener support?
  • Is the system read-heavy or write-heavy?
  • How many requests per second should we support?
  • Do we need analytics?
  • Do shortened URLs expire?
  • Do users need accounts?
  • Do we need custom short links?
  • Should we prevent malicious links?
  • What is the expected availability?
  • What latency is acceptable?

For this article, we’ll define a reasonable interview scope.


Functional Requirements

The system should support the following core features:

1. Shorten a URL

Given a long URL, the system should return a shortened URL.

Example:

POST /shorten
{
  "long_url": "https://www.example.com/some/long/path"
}

Response:

{
  "short_url": "https://short.ly/aB3xY9"
}

2. Redirect a Short URL

Given a short URL, the system should redirect the user to the original long URL.

Example:

GET /aB3xY9

Response:

HTTP/1.1 301 Moved Permanently
Location: https://www.example.com/some/long/path

Or:

HTTP/1.1 302 Found
Location: https://www.example.com/some/long/path

Users may be allowed to create custom aliases.

Example:

https://short.ly/my-product-launch

Some short links may expire after a certain time.

Example:

expires_at = 2026-12-31T23:59:59Z

5. Basic Analytics

The system may track:

  • Number of clicks
  • Referrer
  • User agent
  • Country
  • Device type
  • Timestamp

6. User Accounts

Optional but common:

  • Users can view their created links
  • Users can delete links
  • Users can manage analytics
  • Users can set expiration dates

Non-Functional Requirements

Non-functional requirements are often more important than functional requirements in system design interviews.

1. Low Latency

Redirects should be extremely fast.

Target:

Redirect latency < 100 ms

Ideally:

Redirect latency < 50 ms

2. High Availability

URL shorteners are often used in public links, marketing campaigns, and social media. Downtime is unacceptable.

Target:

99.99% availability

3. Scalability

The system should handle a large number of read requests.

URL shortening systems are typically read-heavy.

For example:

  • Many users click shortened links.
  • Fewer users create shortened links.

A typical read/write ratio could be:

90% reads
10% writes

Or even:

99% reads
1% writes

4. Reliability

Shortened URLs should not disappear.

If a short link is created, it should reliably resolve to the original URL unless intentionally deleted or expired.

5. Consistency

For most URL shorteners, strong consistency is not always necessary for analytics, but the mapping between short code and long URL should be reliable.

We can tolerate eventual consistency for analytics but not for core redirects.

6. Security

The system should protect against:

  • Malicious URLs
  • Spam
  • Brute-force enumeration
  • Abuse by bots
  • Phishing links
  • SQL injection
  • XSS if links are displayed in a dashboard

Step 2: Estimate Capacity

Capacity estimation helps demonstrate engineering maturity.

Let’s make reasonable assumptions.

Assumptions

Suppose our system receives:

100 million new URLs per month

And:

10 billion redirects per month

This gives a read/write ratio of:

10,000,000,000 / 100,000,000 = 100:1

So the system is heavily read-dominant.

Writes Per Second

100 million writes per month

Approximate seconds per month:

30 days × 24 hours × 3600 seconds = 2,592,000 seconds

Writes per second:

100,000,000 / 2,592,000 ≈ 38.6 writes/sec

We can round this to:

~40 writes/sec

Reads Per Second

10 billion reads per month

Reads per second:

10,000,000,000 / 2,592,000 ≈ 3,858 reads/sec

We can round this to:

~4,000 reads/sec

Peak Traffic

Systems often need to handle 2x to 5x average traffic.

If we assume 5x peak:

Writes: 40 × 5 = 200 writes/sec
Reads: 4,000 × 5 = 20,000 reads/sec

So our system should be designed to handle:

20,000 reads/sec
200 writes/sec

Storage Estimation

Assume each URL record contains:

FieldSize
short_code10 bytes
long_url500 bytes
created_at8 bytes
expires_at8 bytes
user_id8 bytes
metadata100 bytes

Approximate record size:

~650 bytes

If we store 100 million URLs per month:

100,000,000 × 650 bytes = 65 GB per month

Per year:

65 GB × 12 = 780 GB/year

For five years:

780 GB × 5 = 3.9 TB

So storage is significant but manageable with distributed storage and archival policies.

If we store analytics events, storage grows much faster.

For example, if each redirect produces an analytics event:

10 billion events/month

If each event is 200 bytes:

10,000,000,000 × 200 bytes = 2 TB/month

Analytics data can quickly become larger than the URL mapping data.

Therefore, analytics should usually be stored separately from the core URL mapping database.


Step 3: Define the Core Data Model

The most important data structure is a mapping:

short_code -> long_url

Example:

short_codelong_url
aB3xY9https://www.example.com/very/long/url

The short code must be:

  • Unique
  • URL-safe
  • Short
  • Difficult to guess
  • Efficient to index

How Long Should the Short Code Be?

Short codes are usually generated using characters from:

a-z
A-Z
0-9

This gives:

26 lowercase + 26 uppercase + 10 digits = 62 characters

This is called Base62 encoding.

Number of possible codes for length n:

62^n

For length 6:

62^6 = 56,800,235,584

That is approximately:

56.8 billion combinations

For many systems, a 6-character short code is enough.

For larger scale, use 7 characters:

62^7 = 3,521,614,606,208

That is over 3.5 trillion combinations.

A good default choice:

6 to 7 characters

Step 4: Choose an ID Generation Strategy

The core challenge is generating a unique short code for every long URL.

There are several possible strategies.


Option 1: Hash the Long URL

One simple idea is to hash the long URL using MD5, SHA-1, or SHA-256, then encode the result.

Example:

SHA-256(long_url) -> Base62 -> first 7 characters

Advantages

  • Simple
  • Same long URL produces the same short code
  • Reduces duplicate entries

Disadvantages

  • Hash collisions are possible
  • Need collision detection and resolution
  • Predictable if the same URL always maps to the same short code
  • May leak information about repeated URLs

Collision handling is required.

If two different long URLs generate the same short code, the system must append extra data and hash again, or use another resolution mechanism.


Option 2: Random Short Code Generation

Generate a random 6 or 7 character Base62 string.

Example:

aB3xY9

Then check if it already exists in the database.

If it exists, generate another one.

Advantages

  • Simple to understand
  • Harder to enumerate than sequential IDs
  • No direct relationship between URLs

Disadvantages

  • Database lookup required for every generation
  • Collision probability increases as codes are used
  • May become slow under heavy write load unless optimized

This is acceptable for small systems but not ideal for massive scale.


Option 3: Distributed Unique ID Generator

A more scalable approach is to use a centralized or distributed unique ID generator.

The system generates a unique numeric ID, then converts it to Base62.

Example:

ID = 123456789
Base62(ID) = aB3xY9

This is one of the most common production-ready approaches.

Possible implementations:

  • Database auto-increment ID
  • Redis INCR
  • Snowflake-like ID generator
  • ZooKeeper sequence generator
  • Dedicated ID generation service
  • Key-value store counter
  • Database sequence

Why Base62 Encoding Works Well

Suppose we generate a unique numeric ID:

125000000

We can convert it to Base62:

Base62(125000000) -> short_code

This gives us:

  • Compact representation
  • URL-safe characters
  • No special characters
  • Efficient lookup
  • Deterministic conversion

Base62 avoids characters that may cause issues in URLs, such as:

/
+
=
?
&

Unlike Base64, Base62 is safe for direct use in URLs.


Handling Collisions

Even with unique ID generation, collisions should be considered.

With a unique numeric ID converted to Base62, collisions should not occur if the ID generator is truly unique.

However, with hashing or random generation, collisions must be handled.

Possible strategies:

  1. Check if short code exists.
  2. If it exists, generate a new code.
  3. Append random suffix and retry.
  4. Use database unique constraint.
  5. Use conditional write.

Example database constraint:

UNIQUE(short_code)

If a collision occurs, retry with a new short code.


Step 5: Design the API

A clean API design is essential.

We’ll use REST-style APIs for simplicity.


Create Short URL

Request

POST /v1/shorten

Body:

{
  "long_url": "https://www.example.com/products/laptop?ref=homepage",
  "custom_code": "summer-sale",
  "expires_at": "2026-12-31T23:59:59Z"
}

Response

{
  "short_code": "summer-sale",
  "short_url": "https://short.ly/summer-sale",
  "long_url": "https://www.example.com/products/laptop?ref=homepage",
  "created_at": "2026-06-01T12:00:00Z",
  "expires_at": "2026-12-31T23:59:59Z"
}

Redirect Short URL

Request

GET /{short_code}

Example:

GET /aB3xY9

Response

HTTP/1.1 302 Found
Location: https://www.example.com/products/laptop?ref=homepage

Request

GET /v1/links/{short_code}

Response

{
  "short_code": "aB3xY9",
  "long_url": "https://www.example.com/products/laptop?ref=homepage",
  "created_at": "2026-06-01T12:00:00Z",
  "expires_at": "2026-12-31T23:59:59Z",
  "click_count": 15423
}

Request

DELETE /v1/links/{short_code}

Response

{
  "message": "Link deleted successfully"
}

Get Analytics

Request

GET /v1/links/{short_code}/analytics

Response

{
  "short_code": "aB3xY9",
  "total_clicks": 15423,
  "clicks_last_24_hours": 532,
  "top_countries": [
    {
      "country": "US",
      "clicks": 7200
    },
    {
      "country": "IN",
      "clicks": 3100
    }
  ]
}

Step 6: Choose the Right Database

The primary query pattern is:

SELECT long_url
FROM urls
WHERE short_code = ?

This is a simple key-value lookup.

The database should support:

  • Low-latency reads
  • Unique constraints
  • Horizontal scaling
  • High availability
  • Efficient indexing

Possible options:

Database TypeExamplesGood Fit?
Relational DBPostgreSQL, MySQLYes, for structured data
NoSQL Key-ValueDynamoDB, Redis, CassandraExcellent for scale
Document DBMongoDBPossible but not ideal
Object StorageS3Not ideal for primary lookup

For a large-scale URL shortener, a distributed key-value store or wide-column store is often ideal.

Examples:

  • Amazon DynamoDB
  • Apache Cassandra
  • ScyllaDB
  • Redis with persistence
  • HBase
  • Google Cloud Bigtable

For smaller systems, PostgreSQL or MySQL can work very well.


Example SQL Schema

CREATE TABLE urls (
    id BIGINT PRIMARY KEY,
    short_code VARCHAR(16) NOT NULL UNIQUE,
    long_url TEXT NOT NULL,
    user_id BIGINT,
    created_at TIMESTAMP NOT NULL,
    expires_at TIMESTAMP,
    is_deleted BOOLEAN DEFAULT FALSE
);
CREATE INDEX idx_short_code ON urls(short_code);

If using PostgreSQL:

CREATE INDEX idx_urls_short_code ON urls(short_code);

If custom codes are common, also consider:

CREATE INDEX idx_user_id ON urls(user_id);

Example NoSQL Design

For DynamoDB or Cassandra:

URL Table

Partition key:

short_code

Attributes:

short_code
long_url
created_at
expires_at
user_id
is_deleted

Example item:

{
  "short_code": "aB3xY9",
  "long_url": "https://www.example.com/products/laptop",
  "created_at": "2026-06-01T12:00:00Z",
  "expires_at": null,
  "user_id": "987654",
  "is_deleted": false
}

This gives O(1) lookup by short code.


Step 7: High-Level Architecture

A basic high-level architecture looks like this:

Client
  ↓
Load Balancer
  ↓
API Gateway / Application Servers
  ↓
URL Service
  ↓
Primary Database

For reads:

Client → Load Balancer → Redirect Service → Cache → Database

For writes:

Client → Load Balancer → URL Creation Service → ID Generator → Database

Detailed Architecture Components

1. Client

The client can be:

  • Web browser
  • Mobile app
  • API consumer
  • Admin dashboard

2. Load Balancer

Distributes incoming traffic across application servers.

Examples:

  • NGINX
  • HAProxy
  • AWS ALB
  • Google Cloud Load Balancer
  • Azure Load Balancer

3. API Gateway

Handles:

  • Authentication
  • Rate limiting
  • Request validation
  • Routing
  • Throttling
  • Logging
  • API versioning

4. URL Shortening Service

Handles:

  • Creating shortened URLs
  • Validating input
  • Generating short codes
  • Saving mappings

5. Redirect Service

Handles:

  • Looking up short codes
  • Redirecting users
  • Checking expiration
  • Emitting analytics events

In early designs, this can be the same service as the URL shortening service.

At scale, separate services are better.

6. Cache

Stores frequently accessed short-code-to-long-URL mappings.

Examples:

  • Redis
  • Memcached
  • CDN edge cache

7. Primary Database

Stores durable URL mappings.

8. Message Queue

Handles asynchronous analytics processing.

Examples:

  • Apache Kafka
  • AWS Kinesis
  • RabbitMQ
  • Google Pub/Sub

9. Analytics Pipeline

Processes click events.

Components:

  • Stream processor
  • Data warehouse
  • Aggregation service
  • Dashboard

Step 8: Read Flow

When a user clicks a shortened URL:

https://short.ly/aB3xY9

The system performs the following steps:

  1. Request reaches load balancer.
  2. Load balancer routes request to redirect service.
  3. Redirect service checks cache.
  4. If cache hit, return long URL.
  5. If cache miss, query database.
  6. Store result in cache.
  7. Return redirect response.
  8. Emit click event asynchronously.

Example:

GET /aB3xY9

Cache lookup:

short_code = aB3xY9

Cache hit:

long_url = https://www.example.com/products/laptop

Response:

HTTP/1.1 302 Found
Location: https://www.example.com/products/laptop

Step 9: Write Flow

When a user creates a shortened URL:

  1. Client sends long URL to API.
  2. API validates URL.
  3. System checks rate limits.
  4. ID generator creates unique ID.
  5. Unique ID is encoded into Base62.
  6. Mapping is stored in database.
  7. Short URL is returned to client.

Example:

POST /v1/shorten

Body:

{
  "long_url": "https://www.example.com/products/laptop"
}

ID generator:

ID = 9876543210

Base62:

short_code = aB3xY9

Store:

aB3xY9 -> https://www.example.com/products/laptop

Return:

{
  "short_url": "https://short.ly/aB3xY9"
}

Step 10: Caching Strategy

Since the system is read-heavy, caching is essential.

A large percentage of clicks usually go to a small percentage of popular links.

This is a classic case where the Pareto principle applies:

80% of clicks may come from 20% of links

Or even:

95% of clicks may come from 1% of links

Therefore, caching popular short codes dramatically reduces database load.


What Should Be Cached?

Cache the mapping:

short_code -> long_url

Example:

Key: aB3xY9
Value: https://www.example.com/products/laptop
TTL: 24 hours

You may also cache:

short_code -> metadata

But for redirect performance, only the long URL is needed.


Cache Eviction Policies

Possible eviction policies:

  • LRU: Least Recently Used
  • LFU: Least Frequently Used
  • TTL-based expiration

For URL shorteners, TTL plus LRU is often effective.

Example:

TTL = 1 hour
Max memory = 16 GB
Eviction = allkeys-lru

Cache Invalidation

Cache invalidation is needed when:

  • A link is deleted
  • A link expires
  • A link is updated
  • A link is disabled for abuse

For simplicity, use TTL expiration.

For stronger correctness, invalidate explicitly:

DELETE cache_key

Example:

DEL aB3xY9

If link updates are rare, TTL-only invalidation may be sufficient.


Handling Cache Misses

If a short code is not in cache:

  1. Query database.
  2. If found, write to cache.
  3. Return redirect.
  4. If not found, return 404.

To protect the database from cache stampedes, use:

  • Request coalescing
  • Mutex locks
  • Negative caching
  • Rate limiting

Example negative cache:

Key: aB3xY9
Value: NOT_FOUND
TTL: 60 seconds

Step 11: Use a CDN for Extra Performance

A CDN can improve redirect performance by caching responses closer to users.

However, URL redirects are often personalized or analytics-sensitive, so caching at the CDN requires care.

A CDN can help with:

  • Static assets
  • Public landing pages
  • Rate-limited redirect responses
  • Edge caching for popular links

For redirects, edge logic can:

  • Check cache
  • Forward misses to origin
  • Add analytics headers
  • Enforce geo-based routing
  • Block malicious traffic

Examples:

  • CloudFront Functions
  • Cloudflare Workers
  • Fastly Compute
  • Akamai EdgeWorkers

Step 12: Redirect Status Codes

An important interview discussion is whether to use:

301 Moved Permanently

or:

302 Found

301 Redirect

Meaning:

The resource has permanently moved.

Browsers and CDNs may cache the redirect.

Advantages:

  • Faster future redirects
  • Less server load

Disadvantages:

  • Analytics may be lost because browser does not hit the shortener again
  • Harder to change destination later

302 Redirect

Meaning:

The resource has temporarily moved.

Browsers usually do not cache the redirect aggressively.

Advantages:

  • Better analytics
  • Destination can change
  • More control

Disadvantages:

  • More traffic to redirect service
  • Higher load

For URL shorteners with analytics, 302 is often preferred.

For pure performance without analytics, 301 may be acceptable.

A strong interview answer:

I would use 302 redirects by default because analytics are important. If caching and lower load become more important than click tracking, we can selectively use 301 for certain links or cache popular redirects at the edge.


Step 13: Scalability Considerations

The system must handle high read traffic.

Key scaling techniques:

  1. Horizontal scaling of application servers
  2. Load balancing
  3. Distributed cache
  4. Database replication
  5. Database sharding
  6. Read replicas
  7. Message queues for analytics
  8. CDN caching
  9. Rate limiting
  10. Async processing

Scaling the Application Tier

Use stateless application servers.

Stateless design allows:

  • Easy horizontal scaling
  • Simple load balancing
  • Faster failover
  • Deployment without session affinity

Example:

NGINX Load Balancer
  ├── Redirect Service Instance 1
  ├── Redirect Service Instance 2
  ├── Redirect Service Instance 3
  └── Redirect Service Instance N

Scaling the Database

For small to medium scale, use:

Primary DB + Read Replicas

Writes go to primary.

Reads can go to replicas.

Example:

Write: Primary PostgreSQL
Read: PostgreSQL Read Replica

For larger scale, use sharding.


Database Sharding

Sharding divides data across multiple database nodes.

Possible shard keys:

  • short_code
  • user_id
  • created_at
  • hashed short_code

For redirect lookups, sharding by short_code is usually best.

Example:

shard_id = hash(short_code) % number_of_shards

This allows the system to locate the correct shard quickly.


Consistent Hashing

If using distributed storage, consistent hashing can help distribute keys evenly.

Benefits:

  • Balanced load
  • Easier node addition/removal
  • Reduced reshuffling

Examples:

  • Cassandra
  • DynamoDB
  • Riak
  • Memcached clients
  • Redis Cluster

Step 14: High Availability and Fault Tolerance

A URL shortener should remain available even if some components fail.

Techniques:

  • Multi-zone deployment
  • Multi-region replication
  • Database replicas
  • Cache replicas
  • Health checks
  • Automatic failover
  • Load balancer retries
  • Graceful degradation

Handling Database Failure

If the primary database fails:

  • Promote a replica
  • Route writes to new primary
  • Continue serving reads from cache and replicas
  • Queue writes if necessary

If cache fails:

  • Fall back to database
  • Use request throttling
  • Use negative caching
  • Rebuild cache gradually

Step 15: Analytics Design

Analytics are often a major part of real-world URL shorteners.

Each click can generate an event:

{
  "short_code": "aB3xY9",
  "timestamp": "2026-06-01T12:00:00Z",
  "ip_hash": "hashed_ip",
  "user_agent": "Mozilla/5.0...",
  "referrer": "https://twitter.com",
  "country": "US",
  "device_type": "mobile"
}

Do not block the redirect on analytics processing.

Instead:

Redirect first, analytics later

Use a message queue:

Redirect Service → Kafka → Analytics Pipeline

This keeps redirect latency low.


Analytics Architecture

A scalable analytics pipeline:

Redirect Service
  ↓
Kafka/Kinesis
  ↓
Stream Processor
  ↓
Aggregated Storage
  ↓
Analytics API/Dashboard

Possible technologies:

ComponentOptions
Message QueueKafka, Kinesis, RabbitMQ
Stream ProcessingFlink, Spark Streaming, Kafka Streams
StorageClickHouse, BigQuery, Snowflake, Druid
Real-Time MetricsRedis, DynamoDB
DashboardsGrafana, Superset, custom UI

Real-Time Click Counter

For basic click counts, use Redis:

INCR clicks:aB3xY9

Example:

Key: clicks:aB3xY9
Value: 15423

For time-based analytics:

INCR clicks:aB3xY9:2026-06-01:12

This allows clicks per hour.


Step 16: Security and Abuse Prevention

URL shorteners can be abused for:

  • Phishing
  • Malware distribution
  • Spam
  • Ad fraud
  • Bot traffic
  • Brute-force scanning

Security measures are important.


1. URL Validation

Validate the long URL:

  • Must be a valid URL
  • Must use allowed schemes, usually http or https
  • Reject suspicious domains
  • Check maximum length

Example:

Allowed schemes: http, https
Max URL length: 2048 characters

Integrate with:

  • Safe Browsing APIs
  • Virus scanning services
  • Domain reputation systems
  • ML-based fraud detection

If a link is malicious:

  • Block creation
  • Disable redirect
  • Show warning page
  • Report abuse

3. Rate Limiting

Prevent abuse by limiting API calls.

Examples:

Anonymous user: 10 links/minute
Authenticated user: 100 links/minute
IP-based redirect limit: 1000 requests/minute

Use:

  • Token bucket
  • Sliding window
  • Redis-based counters

4. Authentication and Authorization

For user-owned links:

  • Require API keys or OAuth
  • Verify ownership before deletion/update
  • Scope permissions

Example:

Authorization: Bearer <token>

5. Prevent Enumeration

Sequential IDs are easy to enumerate.

Example:

/aB3xY0
/aB3xY1
/aB3xY2

To reduce enumeration risk:

  • Use random-looking Base62 codes
  • Avoid exposing internal IDs
  • Add rate limiting
  • Use longer codes if needed

However, if codes are generated from sequential IDs and Base62 encoded, they may still be somewhat predictable. If unpredictability is important, add randomization or encryption.


Custom links improve branding.

Example:

https://short.ly/summer-sale

Challenges:

  • Must be unique
  • May contain reserved words
  • May be abusive
  • May require validation

Implementation:

  1. User requests custom code.
  2. System validates format.
  3. System checks availability.
  4. If available, reserve atomically.
  5. Store mapping.

Use database unique constraint:

UNIQUE(short_code)

Or conditional write in DynamoDB:

attribute_not_exists(short_code)

Reserved words should be blocked:

admin
api
login
dashboard
settings
help
support

Some links should expire.

Example:

expires_at = 2026-12-31T23:59:59Z

On redirect:

if current_time > expires_at:
    return 404 or 410

To avoid scanning the database constantly, use:

  • TTL in cache
  • Background cleanup jobs
  • Time-to-live indexes
  • Lazy expiration during read
  • Scheduled deletion tasks

Example lazy expiration:

Read short_code
If expired:
    return 404
    mark as expired

Step 19: Multi-Region Design

For global scale, deploy across regions.

Example:

US-East
EU-West
AP-South

Each region can have:

  • Application servers
  • Cache
  • Read replicas
  • Message queue
  • CDN edge

Writes can be:

  • Single-region primary
  • Multi-region active-active
  • Region-local writes with async replication

For simplicity, many systems use:

Single write region
Multiple read regions

For higher availability:

Active-active multi-region

But this introduces conflict resolution complexity.


Step 20: Consistency Tradeoffs

The URL mapping must be reliable.

If a short code is created, users should be able to resolve it quickly.

This suggests strong consistency for writes or at least read-after-write consistency.

For analytics, eventual consistency is acceptable.

A good tradeoff:

Data TypeConsistency Model
short_code to long_urlStrong or read-after-write
click analyticsEventual
dashboard metricsEventual
abuse flagsNear real-time
custom link reservationStrong

Step 21: Monitoring and Observability

A production system needs monitoring.

Track:

  • Redirect latency
  • Cache hit ratio
  • Database query latency
  • Error rate
  • 404 rate
  • 5xx rate
  • QPS
  • CPU/memory usage
  • Queue lag
  • Analytics pipeline delay
  • Rate-limit rejections

Example metrics:

p50 redirect latency
p95 redirect latency
p99 redirect latency
cache_hit_rate
database_read_latency
kafka_consumer_lag

Use:

  • Prometheus
  • Grafana
  • Datadog
  • New Relic
  • CloudWatch
  • OpenTelemetry

Step 22: Possible Failure Scenarios and Mitigations

Scenario 1: Cache Failure

Impact:

Increased database load

Mitigation:

  • Cache replicas
  • Fallback to database
  • Rate limiting
  • Request coalescing

Scenario 2: Database Overload

Impact:

Slow redirects
Timeouts

Mitigation:

  • Add read replicas
  • Increase cache TTL
  • Serve stale cache temporarily
  • Shard database
  • Throttle non-critical traffic

Scenario 3: ID Generator Failure

Impact:

Cannot create new links

Mitigation:

  • Highly available ID generator
  • Preallocated ID ranges
  • Fallback generator
  • Retry with backoff

Scenario 4: Analytics Pipeline Failure

Impact:

Analytics delayed or lost

Mitigation:

  • Durable queue
  • Replay events
  • Dead-letter queue
  • Monitoring lag

Redirects should continue to work even if analytics fails.


Step 23: Optimizations for Low Latency

To make redirects extremely fast:

  1. Cache hot links.
  2. Use CDN edge caching.
  3. Keep redirect service stateless.
  4. Use connection pooling.
  5. Use asynchronous analytics.
  6. Avoid heavy processing in redirect path.
  7. Use efficient serialization.
  8. Use HTTP/2 or HTTP/3.
  9. Deploy close to users.
  10. Index short_code efficiently.

The redirect path should be as lightweight as possible.


Step 24: Example System Design Answer Structure

In an interview, structure your answer like this:

1. Clarify Requirements

I’d like to start by clarifying the scope. Are we building a basic TinyURL-like service with redirect and analytics? Is it read-heavy? Do we need custom links, user accounts, and expiration?

2. Define Functional Requirements

Core features are shortening a URL, redirecting to the original URL, optional custom aliases, expiration, and analytics.

3. Define Non-Functional Requirements

The system should be highly available, low latency, scalable, and reliable. It is likely read-heavy.

4. Estimate Scale

If we assume 100 million links created per month and 10 billion redirects per month, we need around 4,000 reads/sec and 40 writes/sec on average, with peak around 20,000 reads/sec.

5. Data Model

The core table maps short_code to long_url. The short_code should be unique and indexed.

6. ID Generation

I would use a distributed unique ID generator and convert IDs to Base62. This avoids collisions and scales well.

7. API Design

We need a POST endpoint to create links and a GET endpoint to redirect.

8. High-Level Architecture

Clients connect through a load balancer to stateless API servers. URL mappings are stored in a scalable database. A cache handles hot reads.

9. Caching

Use Redis or CDN caching for popular links. Cache the short_code to long_url mapping.

10. Analytics

Emit click events asynchronously to Kafka and process them separately so redirects remain fast.

11. Tradeoffs

Use 302 redirects for analytics, strong consistency for link creation, eventual consistency for analytics.


Simplified Architecture Diagram

                    ┌────────────┐
                    │   Client   │
                    └─────┬──────┘
                          │
                    ┌─────▼──────┐
                    │    CDN     │
                    └─────┬──────┘
                          │
                    ┌─────▼──────┐
                    │ Load       │
                    │ Balancer   │
                    └─────┬──────┘
                          │
          ┌───────────────┼───────────────┐
          │               │               │
   ┌──────▼─────┐  ┌──────▼─────┐  ┌──────▼─────┐
   │ Redirect   │  │ Redirect   │  │ URL Create │
   │ Service    │  │ Service    │  │ Service    │
   └──────┬─────┘  └──────┬─────┘  └──────┬─────┘
          │               │               │
          │               │        ┌──────▼─────┐
          │               │        │ ID         │
          │               │        │ Generator  │
          │               │        └──────┬─────┘
          │               │               │
   ┌──────▼───────────────▼───────────────▼─────┐
   │                  Cache                     │
   │               Redis/Memcached              │
   └──────────────────┬─────────────────────────┘
                      │
              ┌───────▼────────┐
              │  URL Database  │
              └───────┬────────┘
                      │
              ┌───────▼────────┐
              │ Message Queue  │
              │ Kafka/Kinesis  │
              └───────┬────────┘
                      │
              ┌───────▼────────┐
              │ Analytics      │
              │ Pipeline       │
              └────────────────┘

Sample Database Choices by Scale

Small Scale

Use:

PostgreSQL
Redis Cache
NGINX

Architecture:

App Server → PostgreSQL
App Server → Redis

Good for:

  • Startup product
  • Internal tool
  • Low traffic service

Medium Scale

Use:

PostgreSQL with read replicas
Redis Cluster
Load Balancer
Kafka

Architecture:

Stateless App Servers
Redis Cache
Primary DB + Read Replicas
Kafka for analytics

Good for:

  • Public SaaS
  • Moderate viral traffic
  • Marketing links

Large Scale

Use:

DynamoDB/Cassandra
Redis Cluster
CDN
Kafka/Kinesis
Multi-region deployment

Architecture:

Edge/CDN
Load Balancers
Stateless Redirect Services
Distributed Cache
Distributed Key-Value Store
Async Analytics Pipeline

Good for:

  • Global URL shortener
  • Billions of clicks
  • High availability requirements

Common Interview Follow-Up Questions

1. What happens if two users shorten the same long URL?

Possible approaches:

  • Return the same short code
  • Create different short codes
  • Let users choose custom codes

If deduplicating:

Hash(long_url) -> short_code

But collision handling is still required.

If not deduplicating:

Each request gets a unique ID

This is simpler and often preferred.


2. How do you prevent malicious URLs?

Use:

  • URL validation
  • Domain reputation
  • Safe Browsing APIs
  • Rate limiting
  • Abuse reporting
  • ML classification
  • Manual review

Use:

  • Distributed ID generation
  • Sharded database
  • Caching
  • CDN
  • Stateless services
  • Async analytics

4. How do you make redirects faster?

Use:

  • Cache
  • CDN
  • Read replicas
  • Edge functions
  • Minimal processing
  • Connection reuse

Check expiration during redirect.

Use:

if expires_at < current_time:
    return 404 or 410

Cleanup can happen asynchronously.


6. How do you handle hot keys?

A hot key is a very popular short link receiving massive traffic.

Mitigations:

  • Cache hot key
  • Replicate hot key across cache nodes
  • Use CDN caching
  • Rate limit abusive clients
  • Serve from edge

7. What if the cache becomes inconsistent?

Use:

  • TTL expiration
  • Explicit invalidation
  • Versioned records
  • Write-through or write-around cache patterns

For critical updates, invalidate cache immediately.


Best Practices for a Strong Interview Answer

  1. Start with requirements.
  2. Quantify scale.
  3. Identify read/write ratio.
  4. Keep the core design simple.
  5. Discuss tradeoffs.
  6. Separate analytics from redirect path.
  7. Emphasize caching.
  8. Mention security and abuse prevention.
  9. Use diagrams if possible.
  10. Explain why you choose each component.

Avoid jumping straight into code or database tables.

Interviewers want to see structured thinking.


Example Final Architecture Summary

A strong final design could be:

Client
  ↓
CDN / Edge
  ↓
Load Balancer
  ↓
Stateless Redirect Service
  ↓
Redis Cache
  ↓
Distributed Key-Value Store

For link creation:

Client
  ↓
API Gateway
  ↓
URL Creation Service
  ↓
Distributed ID Generator
  ↓
Distributed Key-Value Store

For analytics:

Redirect Service
  ↓
Kafka
  ↓
Stream Processor
  ↓
Analytics Database

Key design decisions:

  • Use Base62 short codes
  • Use unique ID generator
  • Use 302 redirects
  • Cache hot links
  • Process analytics asynchronously
  • Shard by short_code
  • Rate limit creation and redirect APIs
  • Store analytics separately from URL mappings

Conclusion

Designing a URL shortener is an excellent system design interview question because it starts simple but quickly expands into important distributed systems topics.

A successful answer should cover:

  • Functional and non-functional requirements
  • Capacity estimation
  • API design
  • Data modeling
  • ID generation
  • Caching
  • Redirect behavior
  • Scalability
  • High availability
  • Analytics
  • Security

The key insight is that a URL shortener is a read-heavy, low-latency key-value lookup system. The most important design decisions revolve around fast redirects, efficient key generation, caching, and asynchronous analytics processing.

If you can clearly explain these tradeoffs and present a clean architecture, you will demonstrate strong system design skills.


Frequently Asked Questions

1. Is a URL shortener read-heavy or write-heavy?

A URL shortener is usually read-heavy. Many users click shortened links, while relatively fewer users create new links. The read/write ratio can be 100:1 or higher.


2. What database is best for a URL shortener?

For small systems, PostgreSQL or MySQL is sufficient. For large-scale systems, a distributed key-value store such as DynamoDB, Cassandra, or Bigtable is often better.


3. Why use Base62 instead of Base64?

Base62 uses URL-safe characters only:

a-z
A-Z
0-9

Base64 may include characters like /, +, and =, which can require URL encoding.


4. Should I use 301 or 302 redirects?

Use 302 if analytics are important because browsers may not hit your server again after a cached 301 redirect. Use 301 if performance and caching are more important than analytics.


5. How do you generate unique short codes?

A common approach is to generate a unique numeric ID using a distributed ID generator and convert it to Base62. This avoids collisions and scales well.


6. How do you scale a URL shortener?

Use stateless services, load balancing, caching, database replication, sharding, CDN caching, and asynchronous analytics processing.


7. How do you handle analytics without slowing down redirects?

Send click events asynchronously to a message queue such as Kafka or Kinesis. Process analytics separately from the redirect path.


8. How do you prevent abuse?

Use rate limiting, URL validation, malicious link scanning, authentication, domain reputation checks, and abuse reporting mechanisms.