<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Piyush Deshmukh</title>
    <description>The latest articles on DEV Community by Piyush Deshmukh (@piyush_deshmukh).</description>
    <link>https://dev.to/piyush_deshmukh</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3456339%2F7f33aee4-efcb-4412-8bcd-625deacd7e29.png</url>
      <title>DEV Community: Piyush Deshmukh</title>
      <link>https://dev.to/piyush_deshmukh</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/piyush_deshmukh"/>
    <language>en</language>
    <item>
      <title>Design TinyURL</title>
      <dc:creator>Piyush Deshmukh</dc:creator>
      <pubDate>Sun, 14 Sep 2025 16:15:21 +0000</pubDate>
      <link>https://dev.to/piyush_deshmukh/design-tinyurl-3fm1</link>
      <guid>https://dev.to/piyush_deshmukh/design-tinyurl-3fm1</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;A URL Shortener service takes a long URL (like &lt;a href="https://example.com/some/very/deep/path" rel="noopener noreferrer"&gt;&lt;code&gt;https://example.com/some/very/deep/path&lt;/code&gt;&lt;/a&gt;) and produces a much shorter alias (like &lt;a href="https://short.ly/aBcD12" rel="noopener noreferrer"&gt;&lt;code&gt;https://short.ly/aBcD12&lt;/code&gt;&lt;/a&gt;). Users accessing the short URL are redirected to the original long URL. Examples include &lt;strong&gt;TinyURL&lt;/strong&gt;, &lt;strong&gt;Bitly&lt;/strong&gt;, etc.&lt;/p&gt;

&lt;h2&gt;
  
  
  Functional Requirements
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Features
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Shorten a long URL&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Redirect from Short URL → Long URL&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Analytics&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Users
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;100M DAU (daily active users)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;100:1 read to write ratio&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;1M writes/day&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;500 bytes each entry size&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Data retention for 5 years&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Non-Functional Requirements
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;High Availability -&lt;/strong&gt; The system should be available 24/7, minimal downtime.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Low Latency -&lt;/strong&gt; Redirects should be very fast (~200 ms).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;High Durability -&lt;/strong&gt; Data must persist even if servers crash.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  API Endpoints
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;h3&gt;
  
  
  POST /api/urls/shorten
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Request Body:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "longUrl": "https://example.com/some/very/deep/path"
}
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;&lt;strong&gt;Response Body:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "shortUrl": "https://short.ly/aBcD12"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;h3&gt;
  
  
  GET /:shorturl
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Response Body:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "longUrl": "https://example.com/some/very/deep/path"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  High Level Design
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F53wo1whltmqw4evir9yk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F53wo1whltmqw4evir9yk.png" alt="Initial Design for URL Shortening Service" width="800" height="307"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Initial flow for a URL Shortening service will have:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Client sends a URL to shorten&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The client sends a &lt;code&gt;POST&lt;/code&gt; request to the API Gateway, including the original long URL.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;API Gateway Forwards to URL Shortening Service&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The API Gateway routes the request to the &lt;strong&gt;URL Shortening Service&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;This service:

&lt;ul&gt;
&lt;li&gt;Generates a &lt;code&gt;shortCode&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Saves the mapping (&lt;code&gt;shortCode → longUrl&lt;/code&gt;) in the &lt;strong&gt;database&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Returns the short URL to the client (e.g., &lt;a href="https://short.ly/abc123" rel="noopener noreferrer"&gt;&lt;code&gt;https://short.ly/abc123&lt;/code&gt;&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Client Uses the Short URL&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When anyone clicks the short URL (&lt;a href="https://short.ly/abc123" rel="noopener noreferrer"&gt;&lt;code&gt;https://short.ly/abc123&lt;/code&gt;&lt;/a&gt;), a &lt;code&gt;GET&lt;/code&gt; request is sent to the API Gateway.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;API Gateway Routes to URL Redirection Service&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;Redirection Service&lt;/strong&gt; looks up the short code (&lt;code&gt;abc123&lt;/code&gt;) in &lt;strong&gt;database.&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Redirect to Original URL&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Once the long URL is retrieved, the service responds with a &lt;strong&gt;301 or 302 redirect&lt;/strong&gt; to the original long URL.&lt;/li&gt;
&lt;li&gt;The browser follows this redirect and loads the long URL.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  Optimize Design &amp;amp; Deep Dives
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;How will someone be redirected to original url when clicked on short url?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When someone clicks on short url, the URL Redirection Service finds corresponding short url in DB.
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;And responds with an &lt;strong&gt;HTTP 302 status code&lt;/strong&gt; (or 301), along with the &lt;code&gt;Location&lt;/code&gt; header:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;HTTP 302 Found
Location: https://www.example.com/very/long/path?ref=campaign
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Why use 302 (Found) instead of 301 (Moved Permanently)?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;302 is Temporary:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Tells browsers - "This redirect might change later. Don't cache it permanently."
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;301 is Permanent:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Tells browsers and search engines: "This link will always go to the same place."
&lt;/li&gt;
&lt;li&gt;Browsers will &lt;strong&gt;cache it permanently&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Why use NoSQL DB for a URL Shortener?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;URL shorteners are a perfect fit for NoSQL because they involve simple key-value lookups. For example, you just need to map &lt;code&gt;shortCode → longUrl&lt;/code&gt;, which doesn’t require complex joins or relationships.
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;NoSQL offers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;High read/write throughput&lt;/li&gt;
&lt;li&gt;Schema flexibility (you can add tracking data later)&lt;/li&gt;
&lt;li&gt;Horizontal scalability (easily handle millions of requests)&lt;/li&gt;
&lt;li&gt;Low-latency key-based access
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We can use a highly available DB (eg, DynamoDB or Cassandra) to persist mappings&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;What data should we store in the DB?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;URL&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "shortCode": "abc123",
  "longUrl": "https://www.example.com/very/long/article?id=12345",
  "createdAt": "2025-09-14T10:00:00Z",
  "userId": "77a211ff"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;User&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    {
       "userId": "77a211ff",
       ....
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;As we know URL Shortener is Read heavy, so how can we optimize our system?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Add a Caching Layer (eg. Redis)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cache popular &lt;code&gt;shortCode → longUrl&lt;/code&gt; mappings&lt;/li&gt;
&lt;li&gt;Reduces database reads and latency&lt;/li&gt;
&lt;li&gt;Use TTL or LRU eviction policy to manage memory
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Use indexing on&lt;/strong&gt; &lt;code&gt;shortcode&lt;/code&gt; &lt;strong&gt;in DB&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ensure the DB has a proper index on &lt;code&gt;shortcode&lt;/code&gt; field.&lt;/li&gt;
&lt;li&gt;Speeds up lookup queries for redirection.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;How to generate unique IDs for each long url?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Generating unique, collision-free short codes is &lt;strong&gt;critical&lt;/strong&gt; to the URL shortener’s design. Here are the most common methods:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Auto-Incrementing Counter + Base62 Encoding&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use a global counter that increments for each new URL.
&lt;/li&gt;
&lt;li&gt;Convert the counter number to Base62 (0-9, A-Z, a-z) to get a short, URL-friendly string.&lt;/li&gt;
&lt;li&gt;Example: &lt;code&gt;125 → "cb"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Pros:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Simple, predictable, no collisions.&lt;/li&gt;
&lt;li&gt;Very short codes.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Cons:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Needs centralized counter (hard to scale).&lt;/li&gt;
&lt;li&gt;Sequential URLs can reveal traffic volume.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Random String with Collision Check&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Generate a random Base62 string of fixed length (eg., 6 chars).
&lt;/li&gt;
&lt;li&gt;Check the database for collisions, regenerate if exists.
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Pros:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Easy to scale horizontally.&lt;/li&gt;
&lt;li&gt;Hard to guess next short code (better privacy).
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Cons:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Small collision risk (can be minimized by length).&lt;/li&gt;
&lt;li&gt;Requires DB check on every generation.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Hashing the Long URL&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Hash the original URL (MD5/SHA) and use first N chars as short code.
&lt;/li&gt;
&lt;li&gt;Same long URL always gets same short code.
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Pros:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Idempotent (no duplicates for same URL).&lt;/li&gt;
&lt;li&gt;No centralized state needed.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Cons:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Collision risk.&lt;/li&gt;
&lt;li&gt;Slightly longer or less friendly codes.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;UUID or GUID Encoding&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Generate a UUID, encode in Base62 or hex.
&lt;/li&gt;
&lt;li&gt;Use a substring as the short code.
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Pros:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Globally Unique.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Cons:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Codes are longer.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; For most URL shorteners, especially at &lt;strong&gt;small to medium scale&lt;/strong&gt;, the &lt;strong&gt;Random String + Collision Check&lt;/strong&gt; method offers the best balance.&lt;/p&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;How can we scale the system to handle High Traffic?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Sharding:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;To handle high traffic and scale efficiently, we can use sharding to distribute data and load across multiple machines. This enables &lt;strong&gt;horizontal scaling&lt;/strong&gt;, allowing us to add more nodes as traffic grows without major reconfiguration.
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Load Balancing:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use load balancers to distribute incoming requests evenly across services.&lt;/li&gt;
&lt;li&gt;Prevents any one server from being overloaded.
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;CDN Edge Caching&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use a &lt;strong&gt;CDN (e.g., Cloudflare)&lt;/strong&gt; to cache redirects at edge locations.&lt;/li&gt;
&lt;li&gt;Reduces latency for global users.&lt;/li&gt;
&lt;li&gt;Offloads requests before they even hit your backend.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;/ol&gt;

&lt;h2&gt;
  
  
  Final Design
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7zb0x9us98stnzdkwths.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7zb0x9us98stnzdkwths.png" alt="Final Design for URL Shortening Service" width="800" height="476"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;If you found this post helpful, feel free to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;💬 Drop a comment — I’d love to hear your thoughts or answer your questions!&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;🔁 Share it with others learning system design.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;📌 Follow me here on Dev.to for more deep dives like this!&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thanks for reading! :)&lt;/p&gt;

</description>
      <category>systemdesign</category>
      <category>backend</category>
      <category>architecture</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
