System Design
What Is GeoHashing?
How does an app find the restaurants near you, or the drivers around your location, in milliseconds? Often the answer is geohashing - a clever way to turn a 2D location into a single sortable string that makes 'nearby' fast.
Open a food-delivery app and it instantly shows restaurants near you. Open a ride-sharing app and it finds the drivers around your location in a fraction of a second. Behind these "find what's nearby" features is a hard problem: locations are two-dimensional (latitude and longitude), and efficiently searching "what's close to this point?" across millions of locations is not something a regular database does well.
Geohashing is one of the most elegant solutions. It encodes a two-dimensional location - a latitude and longitude - into a single short string, in such a way that nearby locations have similar strings. That transformation turns a hard 2D proximity problem into a simple 1D string-prefix problem that databases handle effortlessly. This guide explains what geohashing is, how it works (with code), the key property that makes it useful, its tricky edge case, and where it's used.
The problem: searching in two dimensions is hard
To appreciate geohashing, start with the problem. A location is a pair of numbers: latitude and longitude. To find everything "near" a point, you'd naively check the distance from your point to every other point - which means scanning the entire dataset for every query. With millions of locations, that's far too slow.
You might think: just index latitude and longitude separately in a database. But that doesn't work well either. A query like "find points within a few kilometers" becomes "latitude between A and B and longitude between C and D" - and databases struggle to use two separate range conditions efficiently. The two dimensions don't combine into a single index the database can scan quickly. The core difficulty is reducing a 2D proximity question to something a 1D index can answer fast. That's exactly what geohashing does.
The core idea: 2D location → 1D string
Geohashing encodes a latitude/longitude pair into a single string of characters (like dr5ru). The magic property is this:
Locations that are close together have geohashes that share a common prefix.
Two points in the same neighborhood might have geohashes dr5ru7 and dr5ru2 - they share the prefix dr5ru. A point in a different city would have a completely different geohash like 9q8yy. So "find nearby points" becomes "find points whose geohash starts with the same prefix" - a simple, fast string-prefix search that any database with a sorted index can do efficiently.
The length of the geohash controls precision: a longer geohash describes a smaller, more precise area; a shorter one describes a larger area. Truncating a geohash zooms out to a bigger region. This is what makes geohashes so useful for proximity - you pick the prefix length that matches the search radius you want.
graph TD
A[The whole world] --> B[Divide into a grid]
B --> C[Each cell gets a character]
C --> D[Subdivide a cell into a finer grid]
D --> E[Append another character]
E --> F[Longer string = smaller, more precise cell]
This diagram shows the recursive idea behind geohashing. Start with the whole world, divide it into a grid, and give each cell a character. Then subdivide a chosen cell into a finer grid and append another character. The longer the resulting string, the smaller and more precise the cell it identifies.
How it works: recursive subdivision
The mechanism behind geohashing is recursive grid subdivision. Here's the intuition:
- Start with the entire range of possible longitudes (−180 to 180) and latitudes (−90 to 90).
- Repeatedly cut these ranges in half, recording on which side of each cut your point falls. If the point is in the upper half, record a 1; the lower half, a 0. Alternate between cutting longitude and latitude.
- Each cut adds a bit of precision, narrowing down the location to a smaller and smaller cell.
- Group these bits and encode them into characters (geohashes use a base-32 alphabet), producing the final string.
Each character you add to the geohash subdivides the area further, zooming in on a smaller cell. This is why nearby points share prefixes: if two points are in the same large cell, they share the early characters (the coarse subdivisions); they only differ in the later characters (the fine subdivisions), if at all.
Here's a working geohash encoder:
BASE32 = "0123456789bcdefghjkmnpqrstuvwxyz"
def geohash(lat, lon, precision=6):
lat_range, lon_range = [-90.0, 90.0], [-180.0, 180.0]
bit, ch, even, out = 0, 0, True, []
while len(out) < precision:
if even: # bisect longitude
mid = sum(lon_range) / 2
if lon > mid: ch = (ch << 1) | 1; lon_range[0] = mid
else: ch = (ch << 1); lon_range[1] = mid
else: # bisect latitude
mid = sum(lat_range) / 2
if lat > mid: ch = (ch << 1) | 1; lat_range[0] = mid
else: ch = (ch << 1); lat_range[1] = mid
even = not even
bit += 1
if bit == 5: # 5 bits = one base-32 char
out.append(BASE32[ch]); bit = ch = 0
return "".join(out)
# Two nearby points in San Francisco, plus one far away in New York
print("SF point A:", geohash(37.7749, -122.4194)) # near Union Square
print("SF point B:", geohash(37.7752, -122.4191)) # one block away
print("NYC point :", geohash(40.7128, -74.0060)) # across the country
Run it and look at the output: the two San Francisco points share a long common prefix (they're close, so their coarse subdivisions match), while the New York point's geohash is entirely different from the start (it's in a completely different part of the world). That shared prefix is the whole trick - proximity has been encoded into string similarity.
Why this is so useful: proximity becomes prefix search
Now the payoff. Because nearby points share geohash prefixes, finding nearby locations becomes a simple, fast operation:
- Store each location's geohash in a database with a normal sorted index.
- To find points near a target, compute the target's geohash, then search for stored geohashes that share its prefix. Since the database index is sorted, all geohashes with a given prefix sit next to each other - so this is a fast range scan, not a full table scan.
This is the transformation that makes proximity search efficient. A hard 2D problem ("find points within a radius") has become an easy 1D problem ("find strings starting with this prefix"), and databases are extremely good at prefix and range queries on sorted indexes. You also get precision control for free: use a longer prefix for a tighter search radius, a shorter one for a wider area.
The tricky edge case: the boundary problem
Geohashing has one well-known wrinkle that you need to handle, and knowing it is a mark of real understanding. Two points can be physically very close but fall on opposite sides of a grid boundary - giving them completely different geohash prefixes.
Imagine two points just a few meters apart, but right on the line where one grid cell ends and the next begins. Even though they're neighbors, they land in different cells, so their geohashes diverge early and don't share a prefix. A naive prefix search around one point would miss the other, even though it's right next door. This is the boundary problem (or "edge case" in the literal, geographic sense).
The standard fix: when searching, don't just check the target's own geohash cell - also check its neighboring cells. A geohash cell has eight neighbors (north, south, east, west, and the four diagonals). By computing the geohashes of the target cell plus its eight neighbors and searching all nine, you ensure you catch points that are nearby but fall just across a boundary. This neighbor-checking is a routine part of any real geohash-based proximity search.
Warning: The boundary problem is the classic geohashing gotcha. Two points can be meters apart yet have different prefixes if a cell boundary runs between them. Always search the target cell and its neighbors (the eight surrounding cells) to avoid missing nearby points that fall just across an edge. Forgetting this produces a proximity search that mysteriously misses some close-by results.
Where geohashing is used
Geohashing (and closely related spatial-indexing techniques) powers the "find what's nearby" features you use constantly:
- Proximity services like restaurant finders and local search. "Find restaurants near me" becomes a geohash prefix search - fast even across millions of locations.
- Ride-sharing and delivery apps. Matching riders with nearby drivers, or finding delivery partners close to a restaurant, relies on quickly locating points near a target - exactly what geohashing enables.
- Location-based social and dating apps. "Find people near you" is a proximity query over user locations, well suited to geohashing.
- Spatial databases and indexing. Geohashing is one way to build spatial indexes; databases and data stores use it (or relatives like quadtrees) to make geographic queries efficient.
- Map clustering. When a map shows clustered markers ("50 results in this area"), geohash prefixes can group nearby points into clusters cheaply by their shared prefix.
In each case, the core benefit is the same: a fast, index-friendly way to answer "what's near this location?" without scanning everything or struggling with two-dimensional range queries.
Precision levels: how geohash length maps to area
A practical thing to understand is how the length of a geohash relates to the size of the area it describes. Each character added makes the cell roughly an order of magnitude smaller, because each character represents five more bits of subdivision. Approximately:
- A 1-character geohash describes a huge area - thousands of kilometers across.
- A 4-character geohash narrows to roughly a city-sized region (tens of kilometers).
- A 6-character geohash describes an area around a kilometer or so across - a neighborhood.
- An 8-character geohash pinpoints to within roughly a hundred meters or less.
This precision control is enormously useful in practice: you choose the geohash length to match your search radius. Looking for restaurants within a few kilometers? Use a shorter prefix to cover a wide area. Finding the handful of drivers within a couple of blocks? Use a longer prefix for a tight area. By truncating or extending the geohash, you zoom out or in, tuning the search to exactly the granularity you need - all with simple string operations.
Putting it together: designing a "find nearby" service
To see how geohashing assembles into a real feature, sketch a proximity service - "find restaurants near me":
- When a restaurant is added, compute its geohash (to some precision) and store it in the database with a sorted index on the geohash.
- When a user searches, compute the geohash of the user's location at a precision matching the desired radius.
- Find candidates by searching for stored geohashes sharing the user's prefix - a fast range scan on the sorted index - plus the prefixes of the eight neighboring cells, to handle the boundary problem.
- Refine the candidates by computing the exact distance from the user to each, returning those within the true radius, sorted by distance.
The geohash does the heavy lifting: instead of computing the distance to every restaurant (millions of calculations), it instantly narrows the field to the handful in the relevant cells, and only those few need exact distance calculations. That's the difference between a query that scans everything and one that returns in milliseconds. This pattern - geohash to narrow, then exact-distance to refine - is the standard recipe for proximity search.
Note that the same geohash technique powers more than point search - it enables efficient map clustering (grouping nearby points by shared prefix to show "50 results here" at a zoomed-out level) and spatial joins (finding which points fall near which regions). The single idea of encoding location into a sortable, prefix-shareable string turns out to be useful across a whole family of geographic operations, which is a big part of why it's so widely adopted.
Limitations to keep in mind
Geohashing is elegant but not perfect, and naming its limits shows real understanding:
- The boundary problem (covered above) means you must always check neighboring cells, adding a little complexity.
- Uneven cell shapes. Geohash cells aren't perfectly uniform in real-world distance - a degree of longitude covers different distances at different latitudes - so cells are taller or wider depending on where you are. For most proximity uses this is fine, but it's why the final exact-distance refinement step matters.
- Fixed grid. The grid doesn't adapt to data density, so in a dense city a single cell might contain thousands of points while a rural cell contains none. Where adapting to density matters, a quadtree may be a better fit.
These are manageable with the standard techniques (neighbor-checking, distance refinement), and they don't diminish geohashing's core value - they're just the realities you design around.
Related approaches
Geohashing isn't the only way to index spatial data, and it's worth knowing it has relatives:
- Quadtrees recursively divide space into four quadrants, building a tree structure that's especially good when data is unevenly distributed (dense in cities, sparse elsewhere). They adapt to data density in a way fixed geohash grids don't.
- Other spatial indexes (like R-trees and S2 cells) take different approaches to the same goal of making spatial queries fast.
Geohashing's particular strengths are its simplicity, its human-readable string form, and how naturally it fits into ordinary sorted database indexes - you don't need a special spatial database to benefit from it. That accessibility is a big part of why it's so widely used.
Interview: Geohashing is the go-to answer for the "design a proximity service" family of system design questions (find nearby restaurants, drivers, users). Proposing it shows you know how to make 2D proximity search efficient: "I'd geohash each location and store it with a sorted index, so finding nearby points becomes a fast prefix search - and I'd check neighboring cells to handle the boundary case." That last detail about neighbors is what separates a memorized answer from real understanding.
The bottom line
Geohashing encodes a 2D latitude/longitude location into a single string where nearby locations share a common prefix - transforming a hard two-dimensional proximity problem into an easy one-dimensional prefix search that databases handle efficiently. It works by recursively subdividing the map and encoding which cell a point falls into, with longer strings giving finer precision. The main gotcha is the boundary problem (close points can fall in different cells), solved by also searching neighboring cells.
This simple, elegant idea is what makes "find what's nearby" fast across millions of locations, which is why it powers proximity services, ride-sharing, and location-based apps everywhere. We cover spatial indexing and proximity search as part of real system designs across System Design Fundamentals.
Go deeper
- Geohash (Wikipedia) - the encoding, its properties, and the base-32 alphabet.
- Quadtree (Wikipedia) - a related spatial index that adapts to data density.
- Spatial database (Wikipedia) - the broader category of systems for geographic data.
- Redis documentation - geospatial indexing as a practical feature in a real data store.