Rasterflow, Earth Intelligence & inference engine now in public preview Learn More

What is H3? Uber’s Hexagonal Spatial Index

H3 is an open-source geospatial indexing system that divides the Earth into hexagonal cells and gives each cell a 64-bit ID. Uber built H3 to analyze its marketplace by area, then open sourced it in 2018 under the Apache 2 license. The grid has 16 resolutions, from cells the size of a continent to cells under a square meter. Converting latitude and longitude to an H3 cell turns a location into a number that databases can group, sort, and join, which is why H3 shows up in mobility, insurance, retail, and geospatial analysis.

Key takeaways

  • H3 is a hierarchical, hexagonal grid that covers the whole Earth.
  • Every cell has a 64-bit integer ID, usually written in hexadecimal, such as 89283082a33ffff.
  • There are 16 resolutions, 0 to 15, and each hexagon has seven children at the next finer resolution.
  • Hexagons have a single neighbor type, which makes distance and smoothing on the grid simple.
  • Datasets indexed to the same resolution can be joined on the cell ID.

How does H3 work?

H3 starts with an icosahedron, a solid with 20 triangular faces. Uber's engineers chose gnomonic projections centered on each face, so the Earth maps onto the icosahedron, and laid a hexagonal grid on the faces. The result is a geodesic discrete global grid: a set of cells that tiles the sphere.

At resolution 0 the grid has 122 cells: 110 hexagons and 12 pentagons. The H3 resolution table shows that every resolution has exactly 12 pentagons, centered on the icosahedron's vertices. Each finer resolution divides every hexagon into seven smaller hexagons, a scheme called aperture 7. Pentagons have six children.

The H3 index

An H3 cell ID is a 64-bit integer. Its bits store a mode, the resolution, one of the 122 base cells, and up to 15 digits, one per resolution, that select a child at each level. The H3 index documentation defines the canonical string form as lowercase hexadecimal, so the integer 617700169994207231 is written 89283082a33ffff. Store the ID as a 64-bit integer or a string. Casting it through a floating-point type rounds away the last digits and points to the wrong cell.

Approximate containment

Seven hexagons do not fit exactly inside one larger hexagon, so H3 alternates the grid's orientation between resolutions. The H3 indexing overview explains the result: logical containment in the index is exact, and geographic containment is approximate. A point indexed at resolution 9 and truncated to resolution 7 can fall slightly outside the resolution 7 cell's boundary. Cell boundaries at any single resolution are exact.

H3 resolutions

ResolutionAverage hexagon areaAverage edge lengthNumber of cells
04,357,449 km²1,281 km122
312,393 km²69 km41,162
5253 km²9.85 km2,016,842
75.16 km²1.41 km98,825,162
80.737 km²531 m691,776,122
90.105 km²201 m4,842,432,842
100.0150 km²76 m33,897,029,882
12307 m²10.8 m1,660,954,464,122
150.895 m²0.58 m569,707,381,193,162

Values come from the H3 resolution table, which computes areas on a sphere with the WGS 84 authalic radius. Area varies with position: the largest resolution 9 hexagon is about twice the area of the smallest. Resolution 9 cells average about 0.1 km², a useful size for city-scale analysis.

Why hexagons?

The H3 comparison with S2 lays out the trade-off. Squares have two kinds of neighbors: four that share an edge and four that share only a corner, at different distances. Hexagons have one kind: all six neighbors share an edge, and their centers sit at the same distance. Moving objects, smoothing, and spreading effects behave more evenly on a hexagonal grid, because grid distance stands in for geographic distance.

The cost is that hexagons do not nest perfectly. S2 squares split exactly into four children, so S2 containment is exact.

Core H3 operations

  • Point to cell. Find the cell that contains a longitude and latitude at a resolution.
  • Polyfill. Return the cells that cover a polygon, such as a city boundary or a flood zone. H3 version 4 calls it polygonToCells.
  • Grid disk (k-ring). Return all cells within k steps of a cell. One ring returns 7 cells, the cell and its six neighbors, and two rings return 19.
  • Grid distance. Count the steps between two cells.
  • Parent and children. Move up or down the hierarchy with bitwise operations.
  • Compaction. Replace complete sets of children with their parent to store large areas compactly. The H3 documentation shows California shrinking from 10,633 cells to 901 when compacted.
  • Cell to boundary. Return the hexagon polygon for mapping or for an exact geometric check.

H3 vs geohash vs S2

H3S2Geohash
Cell shapeHexagon (plus 12 pentagons per resolution)Square in the S2 projectionRectangle in latitude and longitude
Children per cell7 (approximate containment)4 (exact)Finer with each added character (exact)
Neighbor typesOne (edge)Two (edge, corner)Two (edge, corner)
ID type64-bit integer64-bit integerString
Area distortionAbout 2x between largest and smallest hexagonCells appear distorted on Web Mercator mapsCells shrink toward the poles

The H3 comparison with geohash notes that geohash cells shrink toward the poles, because a degree of longitude spans less distance at high latitudes. String IDs can encode any precision, while H3's fixed 64-bit IDs set a maximum resolution and make integer operations fast.

Choosing an H3 resolution

Pick the resolution from the question and the data:

  • Match the precision of the input. GPS points accurate to about 10 meters do not support resolution 13 cells, so index them at a resolution whose cells are larger than the error.
  • Match the decision. Pricing zones, delivery areas, and store catchments use cells similar in size to the area a decision covers, often resolutions 7 to 9 in cities.
  • Keep counts meaningful. Cells that are too small hold one or zero records each, and cells that are too large blur patterns. Try two or three neighboring resolutions and compare the maps.
  • Store more than one. Because parent IDs come from a few bitwise operations, a table can store a fine resolution and roll up to coarser ones at query time with ST_H3ToParent.

H3 is an index, and cell boundaries approximate real ones. For legal or physical boundaries, such as parcels, flood zones, or city limits, use the H3 join to narrow the candidates, then confirm with an exact geometric predicate such as ST_Intersects on the original geometries. The polygon side must be indexed with full coverage (fullCover = true in ST_H3CellIDs), or points near the polygon's edge can fall in cells the polygon never received and drop out before the exact check.

Common H3 use cases

  • Mobility and marketplaces. Uber uses H3 to set dynamic prices and balance supply and demand by area.
  • Density maps. Count points of interest, trips, or events per cell for an even, comparable map.
  • Joining datasets. Index two datasets to the same resolution and join on the cell ID, then run the exact check. Index polygons with full coverage so no true match is lost, and the cell join becomes a fast pre-filter for a spatial join.
  • Risk scoring. Aggregate hazard layers and exposure to cells for catastrophe modeling and flood risk.
  • Machine learning. Cell IDs give models a consistent spatial unit for features and labels.

H3 in Wherobots

WherobotsDB and Apache Sedona include H3 functions in SQL:

The header image above comes from this query on Overture places in San Francisco. It indexes each place at resolution 9 and counts places per cell:

SELECT CAST(h3 AS STRING) AS h3_cell, lower(hex(h3)) AS h3_index, COUNT(*) AS places
FROM (
  SELECT ST_H3CellIDs(geometry, 9, false)[0] AS h3
  FROM wherobots_open_data.overture_maps_foundation.places_place
  WHERE ST_Intersects(geometry, ST_PolygonFromEnvelope(-122.53, 37.70, -122.35, 37.82))
)
GROUP BY h3
ORDER BY places DESC
LIMIT 5
h3_cellh3_indexplaces
61770016999420723189283082a33ffff2,771
61770016999315865589283082a23ffff2,602
61770016999368294389283082a2bffff1,847
61770017002199449589283082bdbffff1,281
61770016999342079989283082a27ffff1,225

Without the limit, the query returns 1,164 cells. A second query explores the busiest cell:

SELECT lower(hex(ST_H3ToParent(617700169994207231, 7))) AS parent_res7,
       size(ST_H3KRing(617700169994207231, 1, false)) AS ring_1_cells,
       size(ST_H3KRing(617700169994207231, 2, false)) AS ring_2_cells,
       ST_H3CellDistance(617700169994207231, 617700169993158655) AS grid_distance,
       ROUND(ST_AreaSpheroid(ST_H3ToGeom(array(617700169994207231))[0])) AS area_sq_m

The result: its resolution 7 parent is 87283082affffff, one ring holds 7 cells and two rings hold 19, the second-busiest cell is 1 step away, and the hexagon covers 109,461 square meters on the WGS 84 ellipsoid, close to the 105,333 m² average for resolution 9.

A hex count and a count per census tract tell different stories about the same data. Compare this map with the tract-level density map in what is geospatial analysis. Both use the same places from the Havasu catalog.

Read more from Wherobots

Index and aggregate billions of points to H3 cells with a Wherobots free trial at cloud.wherobots.com.

Frequently asked questions

What is H3 by Uber?

H3 is an open-source geospatial indexing system created at Uber that divides the Earth into hexagonal cells at 16 resolutions. Each cell has a 64-bit ID, so any location can be converted to a cell and datasets can be grouped or joined on the ID. Uber open sourced H3 in 2018 under the Apache 2 license.

How does H3 work?

H3 projects the Earth onto the 20 faces of an icosahedron and lays a hexagonal grid on those faces. Resolution 0 has 122 cells. Each finer resolution splits every hexagon into seven smaller ones, an arrangement called aperture 7. A point is indexed by finding the cell that contains it at the chosen resolution.

What is the H3 index level?

The index level, or resolution, sets the cell size. H3 has 16 resolutions, numbered 0 to 15. Resolution 0 hexagons average about 4.36 million square kilometers, resolution 9 hexagons about 0.105 square kilometers, and resolution 15 hexagons under one square meter.

What is H3 polyfill?

Polyfill returns the set of H3 cells that cover a polygon at a given resolution. In H3 version 4 the function is called polygonToCells. In Wherobots and Apache Sedona, ST_H3CellIDs runs polyfill on polygons, and its fullCover option adds cells so the polygon is completely covered.

Why does H3 use hexagons?

Every neighbor of a hexagon shares an edge with it, and all neighbor centers sit at the same distance. Square grids have two kinds of neighbors, edge and corner, at different distances. A single neighbor type makes smoothing, movement, and distance calculations on the grid simpler.

Are all H3 cells hexagons?

No. Every resolution has exactly 12 pentagons, centered on the vertices of the icosahedron. All other cells are hexagons. A pentagon has five neighbors and six children.

What is the difference between H3 and S2?

Both are open-source, hierarchical, global grids with 64-bit cell IDs. S2 uses square cells that split exactly into four children. H3 uses hexagonal cells that split approximately into seven children, which gives uniform neighbors at the cost of approximate geographic containment between resolutions.

What is H3 in Python?

h3-py is the Python binding for the H3 C library. It exposes the core operations, such as converting a point to a cell, getting a cell’s boundary, and finding neighbors. For datasets too large for one machine, the same operations run in SQL with the ST_H3 functions in Wherobots and Apache Sedona.