Skip to main content

How Geohash Turns a Lat/Long Into a Short String You Can Search By Prefix

A practical look at geohash: how each character shrinks the bounding box, why nearby points share a prefix, and how to pick precision against length.

Published By Li Lei
#geohash #geospatial #encoding #developer-tools

How Geohash Turns a Lat/Long Into a Short String You Can Search By Prefix

A latitude and longitude pair is two floating-point numbers. A geohash is one short string of letters and digits that means the same place — u4pruydqqvj instead of 57.64911, 10.40744. That trade looks like a parlor trick until you need to store millions of points and ask "what is near here" without reaching for a spatial database. Then the single-string form starts to earn its keep, because two places that sit close together tend to produce geohashes that start with the same characters. A plain text index can answer a geography question.

This post walks through what each character actually buys you, why the prefix property falls out of the math, and how to choose a length on purpose instead of copying a 9 from a tutorial. You can follow along in the Geohash Converter — type coordinates, watch the string and the bounding box change as you slide the precision.

What the encoding is doing

Geohash is an interleaved binary search. Longitude lives in the range −180 to 180, latitude in −90 to 90. The algorithm repeatedly cuts one of those ranges in half: if your value lands in the upper half it writes a 1, otherwise a 0, and it alternates between longitude and latitude on each step. So the bit stream is longitude, latitude, longitude, latitude, and so on, each bit halving the world along one axis.

Every five bits become one character, drawn from the base32 alphabet 0123456789bcdefghjkmnpqrstuvwxyz. That alphabet deliberately drops a, i, l, and o — the four characters most easily misread or mistyped. If you have ever wondered why a geohash never contains a lowercase L, that is the reason, and it is the same kind of digit-to-symbol mapping you can poke at directly in the base converter when you want to see how a number turns into a non-decimal representation.

The decisive consequence: every character narrows the cell. One character splits the world into 32 boxes. Two characters split each of those into 32 again, giving 1,024 cells. The string is literally a path down a recursive grid, and reading more characters means walking deeper into a smaller box.

Why nearby places share a prefix

Here is the part that makes geohash useful rather than merely clever. Because each character refines the same box that the previous characters already chose, two points inside the same large cell agree on the leading characters before they diverge. The first character pins down a continent-sized region; the points only differ in later characters that describe their position inside it.

Turn that around and you get proximity search almost for free. If you store every location as a geohash string and you want everything inside a given cell, you filter for rows whose geohash starts with that cell's prefix. A B-tree index, a sorted key list, or a Redis sorted set can run that prefix scan cheaply — no geometry, no bounding-box math at query time. This is exactly the mechanism behind Redis GEOADD, Elasticsearch geo_point, and DynamoDB geo libraries. They lean on the prefix property so a string index does the spatial work.

There is one honest catch, and it bites everyone eventually: the grid has hard seams. Two points a single meter apart can land on opposite sides of a cell boundary, which means they share a shorter prefix than their physical closeness suggests. A pure starts-with filter silently misses them. The fix is to query the cell plus its eight neighbors (N, NE, E, SE, S, SW, W, NW) and then filter by true distance. The converter has a "show 8 neighbors" toggle for exactly this — it computes all eight at the same precision so you can see which strings your prefix filter would otherwise skip.

Precision versus length: a sizing table

More characters means a smaller cell and a more exact location. Near the equator the approximate cell sizes are:

  • 5 characters — about 4.9 km (a town or large neighborhood)
  • 6 characters — about 1.2 km (a neighborhood)
  • 7 characters — about 153 m (a city block)
  • 8 characters — about 38 m (a building)
  • 9 characters — about 4.8 m (a storefront entrance)
  • 11 characters — about 15 cm (a survey-grade point, finer than consumer GPS)

Pick the length to match how exact you actually need to be. A city-level grouping is fine at 6. A street address wants 8 or 9. A surveyed point wants 11 or 12. Longer is not "better" — it is just smaller, and a needlessly long hash leaks more precise location data than your feature requires. If you are deciding how much accuracy a privacy feature can afford, a coarse hash is a feature, not a compromise.

A worked example

Take 57.64911, 10.40744, a spot in Denmark and the canonical geohash test coordinate. Encode it at length 11 and you get:

u4pruydqqvj

That string is 55 bits — eleven characters times five bits each — or 55 of those upper-half / lower-half decisions read out five at a time. The first five characters, u4pru, already box you into a roughly 4.9 km cell over northern Denmark; the remaining six characters tighten that box down to about 15 cm on a side. Decode u4pruydqqvj and you get back the center of that final cell, which lands within roughly 15 centimeters of the original point — closer than most phone GPS will ever report.

Now chop it to u4pru (length 5). You have thrown away the fine bits, so decoding returns the center of a 4.9 km box instead of a 15 cm one. Same prefix, far coarser answer. That is the whole length-versus-precision dial in a single example: the prefix you keep determines the size of the box you get back.

Decoding gives you a box, not a point

A geohash names a cell, never a single coordinate, so decoding always returns the cell's center plus an error of half the cell size. The converter reports that as a plus-or-minus value on each axis and draws the full bounding box (the SW and NE corners). This matters more than it sounds. When a service logs a geohash and you need to debug it, the error figure tells you instantly whether the upstream system stored a sloppy 5-character city-level hash or a precise 9-character one — and a precision mismatch is frequently the actual bug, not the coordinates themselves.

I learned that the irritating way. I once spent an afternoon convinced an upstream API was returning the wrong location, re-checking my distance math three times, before I pasted the logged hash into a decoder and saw it was only six characters long. The "wrong" position was just a 1.2 km cell center — the service had stored neighborhood precision and I had been treating it as a street address. Two seconds of decoding would have saved the afternoon, which is exactly why I now decode first and theorize second.

A few traps worth naming

  • Latitude first, longitude second. Latitude runs −90 to 90, longitude −180 to 180. Feed 116.4 into the latitude field and it gets clamped to 90, producing a valid-looking but completely wrong hash. Confirm which number is which before you trust the output.
  • Never trust prefix matching alone. Always include the eight neighbor cells for any radius or nearest-neighbor query, or your search will have blind seams running along every grid line.
  • The decoded center is not your original point. Re-encoding that center returns the same hash, but unless you are at very high precision it is not the coordinate you started with.

Geohash is one of those ideas that feels like sleight of hand and turns out to be plain arithmetic: halve a range, write a bit, alternate axes, group by fives. Once you can see each character as one more cut into a smaller box, the prefix-search property and the precision-versus-length trade stop being magic and become two dials you control. Open the Geohash Converter, type a coordinate you know, and slide the precision until the cell size matches the job in front of you.


Made by Toolora · Updated 2026-06-13