Open elido.me/abc123 and something has to turn that short string into a full web address before your browser can load anything. The mechanism is simpler than most people assume. A URL shortener stores a mapping from a short code to a long destination URL. When you click the short link, the service treats the code as a lookup key, finds the destination, and returns an HTTP redirect that tells your browser where to actually go. One request in, one redirect out.
That is the whole idea. Everything else is engineering around three pressures: make the lookup fast, keep the codes short and unique, and record the click without slowing anyone down. This post walks through how URL shorteners work end to end, using Elido's edge architecture as a concrete example while keeping the explanation true for shorteners in general. We will cover the slug-to-URL mapping, how short codes get generated, where the data lives, the 301-versus-302 redirect choice that trips up more people than anything else, what an HTTP redirect actually looks like on the wire, why caching at the edge matters, and how a click gets counted asynchronously.
How URL Shorteners Work: the Mapping at the Center#
Strip away the infrastructure and a URL shortener is a key-value store with a redirect handler bolted on. The key is the slug, the short code after the domain. The value is the destination, the long URL you originally pasted in.
When you create a short link, the shortener writes one row: this slug points to that destination. When someone visits the short link, the shortener reads that row back and acts on it. Creating links is rare; reading them is constant. A single marketing link might be written once and then read a few hundred thousand times over its life. That read-heavy ratio is the single most important fact about the workload, and it shapes every design decision that follows, especially caching.
The mapping itself can carry more than a destination. In Elido, a slug can hold targeting rules, so one short link routes to different destinations by country, device, language, or time. That is what we call a smart link, and it is still the same lookup, just with a small rule evaluation after the read. The core relationship never changes: slug in, destination out.
Generating the Short Code#
If the slug is the key, where does it come from? There are two well-worn approaches, and most shorteners use one or a blend of both.
The first is base62 encoding of a database ID. Every new link gets an auto-incrementing integer ID from the database. You encode that integer in base62, which uses the 62 URL-safe characters a-z, A-Z, and 0-9. ID 1 becomes b, ID 125 becomes a two-character code, and so on. Base62 is dense: three characters cover about 238,000 links, five characters cover roughly 916 million, six cover about 56 billion. Codes stay short and, because they map one-to-one onto unique IDs, they never collide. The tradeoff is that sequential IDs are guessable, so many systems shuffle or offset the ID space before encoding.
The second approach is random generation. Pick a random string of a fixed length from the same alphabet, then check the database to confirm it is not already taken. If it collides, generate another. Collisions are vanishingly rare at sensible lengths, so the retry loop almost never runs. Random slugs are not enumerable, which is the security argument for them.
Custom slugs, the branded ones like elido.me/spring-sale, sit on top of either scheme. The user supplies the string; the shortener validates it for allowed characters and checks uniqueness against the same index before saving. Whether the slug is generated or hand-picked, it lands in the same place: a unique column in the datastore.
Where the Data Lives#
The slug-to-destination mapping needs a home that can answer "what does this slug point to" quickly and consistently. For the source of truth, that home is almost always a relational database. Elido uses Postgres, with the slug stored as a unique indexed column so a lookup is a single keyed read rather than a table scan. Postgres holds the canonical record for every link, user, and workspace.
But hitting Postgres on every single click would be wasteful given the read-heavy ratio. A keyed slug lookup in Postgres typically runs in one to three milliseconds, which sounds fast until you multiply it by the click volume of a viral link and remember that a database connection is a finite resource. So production shorteners put a cache in front of the database. The cache is where most reads are actually served; the database is the fallback for anything the cache does not have yet.
Elido runs a two-tier cache in front of Postgres. The first tier is an in-process LRU cache living inside the redirect binary itself, which returns a destination in a few hundred nanoseconds with no network hop at all. The second tier is a Redis cluster in the same region, which serves in under a millisecond. Only a cold miss, a slug neither tier has seen recently, falls through to an origin gRPC call against api-core, which reads Postgres. The combined hit rate across both cache tiers sits around 99.4%, so the database is touched on roughly one request in 167. The full breakdown of how that cache behaves, including its eviction policy and the failure modes we have hit, is in our cache strategy writeup.
What an HTTP Redirect Actually Is#
Once the shortener has the destination, it has to hand it back to the browser. It does this with an HTTP redirect, which is just a specific kind of response. Instead of returning page content with a 200 OK, the server returns a 3xx status code and a Location header naming the real URL. On the wire the response is small:
HTTP/1.1 302 Found
Location: https://shop.example.com/spring-collection
Content-Length: 0
The browser reads the status code, sees a Location header, and immediately issues a fresh request to that address. To the person clicking, it looks like one navigation; under the hood it is two requests, with the short link acting as a quick directory lookup in the middle. The semantics of each 3xx code are defined in RFC 7231, and Mozilla's guide to HTTP redirections is the clearest practical reference for which code does what.
The body is empty because there is nothing to render. The entire payload is the status line and the header. This is part of why redirects are cheap to serve: there is no template, no database join for content, no markup. Resolve the slug, set one header, send.
301 vs 302: the Choice That Decides Your Analytics#
Here is where shorteners quietly make a decision that most users never see but that determines whether their link is editable and trackable. The redirect status code is not a formality. The two common options behave very differently.
A 301 Moved Permanently tells the browser, and every proxy and CDN between you and the server, that this short link will always point to the same place. So they cache it. A 301 is aggressively stored. The next time the visitor clicks that short link, their browser may resolve it from cache and never contact the shortener at all. That is great for shaving a round trip, and it is a disaster for a link tool, because two things break. First, analytics go blind: clicks served from the browser cache never reach your server, so they never get counted. Second, the destination is effectively frozen. If you change where the link points, anyone who already cached the 301 keeps landing on the old address until their cache expires, which you do not control.
A 302 Found (and its stricter cousin 307 Temporary Redirect) tells the browser this is temporary: come back and ask again next time. The browser does not cache the mapping, so every click re-requests the short link from the server. That extra round trip is exactly what a link tool wants. Every click reaches your infrastructure, so every click is countable, and because the server resolves the destination fresh each time, you can change where a link points and have the new target take effect on the next click. The cost is one network round trip per click, which a well-built edge keeps in the single-digit milliseconds.
This is why Elido defaults to a 302. Editable destinations and accurate click data are the whole point of a managed link, and a 301 trades both away for a cache optimization you usually do not want. RFC 7231 spells out that a 301 is cacheable by default while a 302 is not stored unless headers say otherwise, which is precisely the behavior the two use cases call for. There are narrow cases where a permanent redirect is correct, a true domain migration, for instance, but for trackable, editable short links the temporary redirect is the right default.
Caching at the Edge for Low Latency#
A redirect is synchronous and blocking. The visitor's browser stalls on the short link until the redirect arrives, and only then can it start loading the page that actually matters. Every millisecond spent resolving the slug is a millisecond added to the visitor's wait. That is why serious shorteners push the lookup as close to the visitor as possible.
Elido runs the redirect handler at edge points of presence in Frankfurt, Ashburn, and Singapore, with traffic routed to the nearest one. The handler is written in Go on top of fasthttp, chosen because its zero-allocation request path keeps garbage-collection pauses predictable under sustained load. Combined with the in-memory cache, this holds redirects to a p95 under 15ms on a cache hit, measured at the POP: roughly 4.8ms median in Frankfurt, climbing to about 14ms p95 in Singapore where the geography is wider. The bulk of that budget is physical network transit, the unavoidable distance between the visitor and the nearest POP, which is the part you cannot optimize away in software. We documented the full latency budget and how each region measures in the p95-under-15ms post.
Putting the lookup at the edge rather than at a single central server is the difference between a redirect that feels instant and one that adds a visible stall. It is also why anycast edge routing beats a DNS-only setup for this workload, a comparison we get into in edge POPs versus DNS-only routing. The short version: the network does the geography, and the cache does the speed.
Counting the Click Without Slowing the Redirect#
A shortener that only redirected would be a redirect service. What makes it a link-management tool is that it counts every click and tells you who clicked, from where, on what device. The hard part is doing that without making the visitor wait for it.
The answer is to decouple the two completely. When the redirect handler resolves a slug, it sends the 302 response right away. Recording the click happens after, as fire-and-forget work. The handler appends a click event, slug, timestamp, a truncated IP, a user-agent hash, onto a message queue and moves on. It does not wait for the write to confirm. If the queue is briefly unavailable, the click is dropped rather than the redirect being delayed; we made the deliberate call that losing a click under infrastructure failure is acceptable and failing a redirect is not.
Elido uses Redpanda as that queue. A separate consumer, the click ingester, reads events off the queue and writes them into ClickHouse, a columnar database built for the kind of high-volume append-and-aggregate workload that click analytics is. The visitor's redirect already completed milliseconds earlier; the analytics row lands a few seconds later, off the hot path entirely. We explain the queue design in fire-and-forget click ingestion and why a columnar store beats Postgres for this in why we use ClickHouse for click analytics.
This decoupling is the reason your analytics can be detailed without being slow. The redirect path stays lean because none of the counting, scoring, or aggregation happens while the visitor waits.
Putting It Together#
A URL shortener, end to end, is a short sequence. You create a link, and the shortener stores a slug-to-destination mapping in Postgres, generating or validating the slug as a unique key. A visitor clicks, the request lands at the nearest edge POP, and the handler resolves the slug from an in-memory cache, falling through to Redis and then the database only on a miss. It returns a 302 with the destination in the Location header, so the click is countable and the destination stays editable. Then it fires the click event onto a queue for a separate consumer to store, without making anyone wait.
Each piece is individually simple. The engineering is in the ratios and the budgets: a read-heavy workload that wants a cache, a latency ceiling that wants the edge, and an analytics requirement that wants to stay off the hot path. If you want to build on this directly, the Smart Links feature exposes the rule layer, the API and SDKs let you mint links from code, and the developer solutions page and edge-redirect architecture docs go deeper on the moving parts. If you are weighing a tool rather than building one, our writeups on what a URL shortener is and whether URL shorteners are safe cover the ground from the user's side, and the pricing page lays out where the free tier ends.