- The request goes to an application server.
- The server creates a short code and stores the
(short_code, long_url)pair in the database. - The server returns the short URL to the user; the user can then share it publicly.
- When anyone later accesses the short link, their request goes to the application server, which looks up the short code in the database and redirects the client to the long URL.
- The code must be short (to keep URLs concise).
- The code must never repeat (no two different long URLs should map to the same short code).
This article compares two common short-code generation strategies — hashing and counting — and highlights trade-offs for scalability, uniqueness, and latency. Use the approach that fits your constraints (statelessness vs guaranteed uniqueness).
Option 1 — Hashing
Idea: take the long URL, pass it through a hash function, and use a fixed-length prefix of the hash as the short code (for example, the first 7 characters). A hash function deterministically converts any input into a fixed jumble of characters. Example:- Deterministic: the same input always produces the same output.
- Not random: identical long URLs always map to the same short code.
- Two different inputs can produce hashes whose first N characters are identical — a collision.
- To avoid collisions, you must check the database when generating a new code. If the code is already taken by a different long URL, modify the input (for example, append a character, use a suffix/salt, or increase the prefix length) and re-hash until you get an unused code.
When to use hashing:
- When you prefer stateless generation and deterministic behavior (same long URL yields same short code).
- When occasional rehash retries are acceptable and traffic/growth is moderate.
Option 2 — Counting (Global Counter)
Idea: maintain a global counter that increments for each new long URL. Convert that integer into a compact alphabet (commonly Base62: 0–9, a–z, A–Z) to produce a short code.
62^7 ≈ 3.5 trillion — large enough for very high-scale needs.
Why counting avoids collisions:
- Each new link gets a unique integer (the counter value). Encoding that integer in Base62 produces a unique short code. No per-generation collision checks are required.
Scaling strategies for the global counter:
- Use a database sequence or an atomic counter service that guarantees monotonic increments.
- Pre-allocate ID ranges to application servers (each server gets a block of IDs to use locally), reducing contention.
- Use distributed ID generators (e.g., Snowflake-style IDs) and encode the generated IDs in Base62 for shortness.
- When you need strict uniqueness without retries and can provision a scalable ID allocation mechanism.
- When shortest possible codes are a priority and you can tolerate a small amount of state management.
Comparison: Hashing vs Counting
Choosing between hashing and counting depends on trade-offs: hashing is stateless but must handle collisions; counting guarantees uniqueness but requires a consistent, scalable way to allocate increasing IDs.
Practical tips
- If you want deterministic short URLs for the same long URL, prefer hashing plus de-duplication logic (dedupe on read/write).
- If you need absolute uniqueness and minimal write-time logic, use a counter-based approach with ID pre-allocation or a distributed ID system.
- Use Base62 (or a larger alphabet) to keep codes compact; increase length only when capacity requires it.
Links and references
- Base62 encoding concepts
- Distributed ID generation (Snowflake)
- Kubernetes – sequences and database techniques for distributed counters