I am not inventing traffic numbers. Without them, the honest design is a solid baseline that scales in the standard read-heavy case.
Priority order for a normal public shortener: redirect latency, redirect availability, mapping durability, horizontal scale, abuse handling, analytics.
Use a clean split between creation, redirect, and metadata lookup.
POST /v1/urls
{"long_url": "https://example.com/some/very/long/path","custom_alias": "spring-sale","expires_at": "2026-12-31T23:59:59Z"}
Success response:
{"short_code": "b9K2xQ","short_url": "https://sho.rt/b9K2xQ","long_url": "https://example.com/some/very/long/path","expires_at": "2026-12-31T23:59:59Z"}
Errors:
GET /{short_code}
Behavior:
GET /v1/urls/{short_code}
Purpose:
Example response:
{"short_code": "b9K2xQ","long_url": "https://example.com/some/very/long/path","status": "active","created_at": "2026-04-02T10:00:00Z","expires_at": null}
One direct design point: I would not assume that the same long URL must always return the same short URL. That is a product decision, not a system-design fact.