Skip to main content

Design a URL Shortener

Design a URL shortening service that converts long URLs into short, shareable links and redirects users to the original URLs.

Related Concepts: Base62 Encoding, Database Sharding, Caching (Redis/Memcached), Load Balancing, Unique ID Generation, CAP Theorem, Read-Heavy Optimization, TTL/Expiration

Step 1: Requirements and Scope​

Functional Requirements​

  • Given a long URL, generate a unique short URL
  • Given a short URL, redirect to the original long URL
  • Support custom short aliases (optional)
  • Support URL expiration (optional)
  • Track click analytics (optional)

Non-Functional Requirements​

RequirementTargetRationale
Availability99.99%Broken links = lost users and revenue
Latency< 100ms redirectUsers expect instant redirects
DurabilityNever lose URLsLinks shared widely must always work
ScalabilityBillions of URLsService grows over time
SecurityNon-guessable URLsPrevent enumeration attacks

Scale Estimation​

  • 100 million new URLs per month (~40 URLs/second)
  • 10:1 read to write ratio -> 1 billion redirects/month (~400 redirects/second)
  • Average URL length: 200 bytes
  • Storage for 5 years: 100M x 12 x 5 x 200 bytes = 1.2 TB (excluding metadata)

How Many Characters for Short Code?​

CharactersBase62 CombinationsYears to Exhaust (at 100M/month)
656.8 billion47 years
73.5 trillion2,900 years
8218 trillion181,000 years

Recommendation: 7 characters provides ample headroom

Step 2: High-Level Design​

Loading diagram...

Step 3: API Design​

Create Short URL​

FieldTypeRequiredDescription
long_urlstringYesOriginal URL to shorten
custom_aliasstringNoUser-specified short code
expires_attimestampNoWhen the link should expire

Response: Short URL with metadata

Redirect Flow​

Loading diagram...

301 vs 302 Redirects​

Redirect TypeBrowser BehaviorAnalyticsSEO
301 PermanentBrowser caches, skips serverUndercounts (cached)Passes link juice
302 TemporaryAlways hits serverAccurate trackingLink juice may not pass

Recommendation: Use 301 for performance, 302 if analytics are critical

Step 4: Short Code Generation Strategies​

Strategy Comparison​

StrategyUniquenessPredictabilityCoordinationComplexity
MD5/SHA HashNeeds collision handlingDeterministicNoneLow
Counter (Auto-increment)Guaranteed uniqueVery predictableCentral counterLow
Random GenerationNeeds collision checkUnpredictableNoneLow
UUID to Base62Very likely uniqueUnpredictableNoneLow
Snowflake IDGuaranteed uniqueSemi-predictableMinimalMedium
Pre-generated PoolGuaranteed uniqueUnpredictablePool managementMedium

Strategy 1: Hash-Based​

Loading diagram...

Pros: Same URL produces same code (deduplication possible) Cons: Collisions require handling, predictable pattern

Strategy 2: Counter-Based (Distributed)​

Loading diagram...

Pros: No collisions, no DB lookup for uniqueness Cons: Sequential patterns reveal traffic volume

Loading diagram...
ComponentBitsPurpose
Sign bit1Always 0 (positive number)
Timestamp41Milliseconds since epoch (69 years)
Machine ID101024 unique machines
Sequence124096 IDs per millisecond per machine

Result: ~4 million IDs/second per machine, globally unique, no coordination

Step 5: Database Design​

Schema Design​

ColumnTypeIndexNotes
idBIGINTPrimary KeySnowflake ID
short_codeVARCHAR(10)Unique IndexThe short URL code
long_urlTEXTNoneOriginal URL (could be very long)
user_idBIGINTIndexOwner of the URL (if authenticated)
created_atTIMESTAMPNoneFor analytics
expires_atTIMESTAMPIndexFor cleanup jobs
click_countBIGINTNoneDenormalized for quick access

Database Choice​

DatabaseProsConsBest For
PostgreSQLACID, mature, indexesVertical scaling limitsModerate scale
MySQLWell-understood, replicationSimilar scaling limitsModerate scale
DynamoDBAuto-scaling, managedEventually consistent, costlyHigh scale, AWS
CassandraLinear scaling, high writeEventual consistencyVery high scale

Recommendation: Start with PostgreSQL with read replicas, migrate to Cassandra/DynamoDB at scale

Sharding Strategy​

Loading diagram...

AWS Alternative: Use Amazon DynamoDB which handles partitioning automatically based on partition key.

Sharding KeyProsCons
short_codeEven distribution, direct lookupsRequires consistent hashing for scaling
user_idGood for user-specific queriesHot users cause hot shards
created_atGood for time-based cleanupRecent shards are hot

Step 6: Caching Strategy​

Cache Architecture​

Loading diagram...

Cache Configuration​

Cache TierTTLSizeHit Rate
CDN24 hoursUnlimited60-70%
Local memory5 minutes10K URLs20-30%
Redis30 days100M URLs95%+

URL access follows Zipf distribution - a small percentage of URLs get most traffic.

Cache Invalidation​

StrategyWhen to Use
TTL-basedDefault for all entries
Write-throughUpdate cache on every write
Delete on expireWhen URL expires or is deleted

Step 7: Analytics (Optional)​

Real-Time Click Tracking​

Loading diagram...

Tracked Metrics​

MetricStorageUse Case
Total clicksCounter in main DBQuick access
Clicks over timeTime-series DBGraphs
Geographic dataAnalytics DBCountry/city breakdown
ReferrerAnalytics DBTraffic sources
Device/browserAnalytics DBUser agent analysis

Step 8: Security Considerations​

Preventing Abuse​

ThreatMitigation
Enumeration attacksRandom codes, not sequential
Malicious URLsURL scanning, blocklist checking
Spam creationRate limiting, CAPTCHA, authentication
URL hijackingOwnership verification for custom aliases

Rate Limiting​

OperationLimitScope
URL creation100/hourPer user/IP
Redirects1000/minutePer short code
Custom alias10/dayPer user

Real-World Systems​

ServiceScaleNotable Features
bit.ly600M clicks/dayEnterprise analytics, branded links
TinyURLOriginal serviceSimple, no account needed
RebrandlyFocused on brandingCustom domains, link management
short.ioAPI-firstWhite-label solution
T.co (Twitter)Billions/dayIntegrated malware scanning

Summary: Key Design Decisions​

DecisionOptionsRecommendation
Code generationHash, Counter, Random, SnowflakeSnowflake ID for uniqueness + time ordering
Code length6-8 characters7 characters (3.5T combinations)
DatabaseSQL, NoSQLPostgreSQL to DynamoDB at scale
CachingRedis, MemcachedRedis Cluster with 30-day TTL
Redirect type301 vs 302301 for performance, 302 for analytics
AnalyticsSync vs AsyncAsync via message queue