Latitude and longitude are precise, and almost useless as a database index. A pair of floating-point numbers tells you exactly where something is, but answering “what else is near this?” means comparing against every other point you hold. At any real scale, that does not work.
Spatial indexing solves it by giving every location on Earth a cell — a discrete, addressable area with an identifier. Two things in the same cell are near each other by definition, and proximity becomes a lookup instead of a calculation.
Three systems dominate: Geohash, S2 and H3. They are not interchangeable, and the differences show up in exactly the queries you will run most.
What a spatial index actually does
Every system here does the same two jobs. It subdivides the surface of the Earth into cells at multiple resolutions, and it assigns each cell an identifier that encodes where it sits in that hierarchy.
The differences come down to three decisions each system made: the shape of the cell, how the sphere is flattened before subdividing, and how identifiers are ordered.
Those choices sound academic. They determine whether your neighbour queries are symmetric, whether aggregating to a coarser resolution is exact or approximate, and how badly cell sizes drift as you move away from the equator.
Geohash
Geohash recursively divides a latitude/longitude rectangle in half, alternating between the two axes, and encodes the result in base32. Each additional character narrows the box.
The defining property is that a shared prefix means spatial containment. Everything inside gcpuv is inside gcpu. That makes proximity searching possible with nothing more than a string index — a genuine advantage if your data already lives in a relational database.
Where it struggles. Cells are lat/lon rectangles, so they narrow steadily towards the poles — a cell in Oslo covers far less ground than one in Nairobi. Neighbours are also asymmetric: the four edge-adjacent cells are closer than the four diagonal ones, so an unweighted “look at surrounding cells” query is subtly biased.
There is also the boundary problem. Two points metres apart can sit either side of a major subdivision and share almost no prefix, so prefix matching alone will miss genuinely close pairs.
S2
S2, from Google, projects the sphere onto the six faces of a circumscribed cube, then runs a quadtree subdivision on each face. Cells are quadrilaterals, and the projection is chosen to keep area distortion low rather than to keep the maths simple.
Cell identifiers are 64-bit integers ordered along a Hilbert curve, a space-filling curve that keeps points close in space close in sort order. That property is why S2 is comfortable in systems built around sorted integer keys and range scans.
S2 runs from level 0 down to level 30, where cells are roughly a centimetre across. Because it is a true quadtree, nesting is exact: every cell decomposes into precisely four children, and rolling up to a coarser level loses nothing.
Where it struggles. Cells are still quadrilaterals, so the diagonal-neighbour asymmetry remains. And identifiers are opaque — you cannot glance at one and infer anything, unlike a Geohash string.
H3
H3, from Uber, tiles the world in hexagons, based on an icosahedron projection, across 16 resolutions from 0 to 15.
Hexagons have one property that neither rectangles nor quadrilaterals can offer: every neighbour is equidistant. A hexagon has exactly six neighbours, all sharing an edge, all the same distance from the centre. For anything involving movement, spread or flow — how traffic moves between areas, how footfall distributes around a site — that symmetry removes a whole class of distortion.
The trade-off is nesting. Hexagons cannot be subdivided into smaller hexagons exactly. H3’s finer resolutions approximate their parents rather than partitioning them, so aggregating between resolutions is slightly lossy. If you need auditable roll-ups, that matters.
There is also a topological quirk worth knowing before it surprises you: you cannot tile a sphere with hexagons alone. Every H3 resolution contains exactly 12 pentagons, inherited from the icosahedron’s vertices. They sit mostly in the ocean, and most workloads never touch one — but code that assumes six neighbours will eventually meet a cell with five.
Compared directly
| Geohash | S2 | H3 | |
|---|---|---|---|
| Cell shape | Lat/lon rectangle | Quadrilateral | Hexagon (plus 12 pentagons) |
| Identifier | Base32 string | 64-bit integer | 64-bit integer |
| Resolutions | ~1–12 characters | Levels 0–30 | Resolutions 0–15 |
| Nesting | Exact, prefix-based | Exact, four children per cell | Approximate |
| Neighbour symmetry | Asymmetric | Asymmetric | Uniform |
| Human readable | Yes | No | No |
| Best at | Prefix search in existing databases | Region covering and exact roll-ups | Aggregation, flow and modelling |
How to choose
The question is not which system is best. It is which query you run most.
Choose Geohash when the index has to live inside a database you already have, when a string index is the mechanism available, or when being able to read an identifier and know roughly where it points has operational value.
Choose S2 when you need exact hierarchical aggregation, when you are covering arbitrary polygons with cells, or when your storage layer is built around sorted integer keys and range scans.
Choose H3 when your analysis is about movement and distribution rather than lookup — binning points for heatmaps, modelling flow between areas, or generating features where an uneven neighbourhood would bias the model.
Plenty of production systems use more than one: H3 for analysis and modelling, S2 or Geohash for storage and retrieval. Converting between them means going back to the underlying coordinates, so store those regardless.
Spatial indexing: common questions
What is a spatial index?
A spatial index divides the Earth’s surface into discrete cells, each with an identifier, so that spatial questions become lookups on those identifiers instead of distance calculations across every record.
Why are hexagons used for spatial data?
Because all six neighbours of a hexagon are the same distance from its centre. Square and rectangular grids have edge neighbours and diagonal neighbours at different distances, which biases any analysis of movement or spread.
Why does H3 have pentagons?
Because a sphere cannot be tiled with hexagons alone. H3 is built on an icosahedron, whose 12 vertices each produce a pentagon at every resolution. They are positioned largely over ocean, but code handling H3 cells should not assume six neighbours.
Is H3 more accurate than Geohash?
Neither is more accurate — accuracy comes from the underlying coordinates. They differ in geometry. H3 gives uniform neighbour distances; Geohash gives readable identifiers and prefix containment. The right answer depends on the query.
Can you convert between Geohash, S2 and H3?
Not directly, because the cell boundaries do not align. Conversion goes via latitude and longitude, which means the original coordinates should always be retained rather than only the cell identifier.
Next steps
Choosing an index is downstream of the data itself. A hexagonal grid does not rescue coordinates that were imprecise to begin with, and no cell system compensates for gaps in coverage.
Our guide to raw geospatial and location data covers what to check in the underlying dataset, and our guide to location data explains the data types these indexes are typically applied to.
James is the head of marketing at Tamoco

