Design: URL shortener
Walk a full small design end to end: key generation, storage, redirects, and the read path.
Open this lesson in the learning hubKey points
- Requirements:
POST /linksreturns a short code,GET /{code}redirects. Roughly 100 reads per write, so optimise the read. - Generate the code from a unique 64-bit id encoded in base62. Seven characters cover 3.5 trillion links, and no collision check is needed.
- Hashing the URL instead means collisions, and collisions mean a read-check-retry loop on the write path. Counters are simpler.
- Storage is tiny: 500 bytes per row × 100M links is about 50 GB. One relational node handles it; the code is the primary key.
- The read path is a key-value lookup, so cache aggressively - hot codes live in Redis and the database is the fallback.
- Redirect with
302if you want click analytics;301is cached by browsers and those hits never reach you again.
Example
// 62^7 = ~3.5 trillion codes. Encode a unique id - never a random guess.
private static final char[] B62 =
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".toCharArray();
static String encode(long id) {
StringBuilder sb = new StringBuilder(7);
do {
sb.append(B62[(int) (id % 62)]);
id /= 62;
} while (id > 0);
return sb.reverse().toString();
}
@RestController
class LinkController {
@PostMapping("/links")
ResponseEntity<LinkResponse> create(@RequestBody @Valid CreateLink req) {
long id = ids.next(); // DB sequence, or a per-instance range
String code = encode(id);
links.save(new Link(code, req.url(), Instant.now()));
return ResponseEntity.created(URI.create("/" + code))
.body(new LinkResponse(code));
}
@GetMapping("/{code}")
ResponseEntity<Void> resolve(@PathVariable String code) {
String url = cache.get(code, links::findUrlOrThrow);
return ResponseEntity.status(HttpStatus.FOUND) // 302: keeps analytics alive
.location(URI.create(url))
.build();
}
}
Unique id plus base62 beats random-and-retry, and the whole read path is one cached lookup.
This is a reading copy. The full lesson — with the visual explainer, the interactive lab and a Run button for the code — lives in the System Design course, and every lesson in it is listed on the System Design contents page.