nim-h3
June 14, 2026 · View on GitHub
High-quality Nim wrapper for the H3 v4 hierarchical hexagonal geospatial indexing system. Embeds the upstream C source — no system library dependencies required.
Quick Start
import h3
# ── Coordinate → cell → coordinate round-trip ──────────────────────
let sf = LatLng(lat: 37.7749, lng: -122.4194)
let cell = latLngToCell(sf, 9).value
echo cell # 0x89283082837ffff
let center = cellToLatLng(cell).value
echo center.lat, ", ", center.lng # 37.77493..., -122.4194...
# ── Cell inspection ────────────────────────────────────────────────
echo cell.resolution # 9
echo cell.isValidCell # true
echo cell.cellToBoundary.value.len # vertex count of hex boundary
# ── String parsing and hex display ─────────────────────────────────
echo $cell # 0x89283082837ffff
let parsed = parseHexCell("89283082837ffff").value
assert parsed == cell
echo cell.h3ToString.value # 89283082837ffff
# ── Neighbors, distances, and paths ────────────────────────────────
for neighbor in gridDisk(cell, 2): # all cells within 2 steps
echo neighbor
echo gridDistance(cell, gridRing(cell, 1).value[0]).value # 1
for c in gridPath(cell, gridRing(cell, 2).value[0]): # shortest line
echo c
# ── Resolution hierarchy ───────────────────────────────────────────
let parent = cellToParent(cell, 5).value
let children = cellToChildren(parent, 7).value # 49 children
echo compactCells(children).value.len # 7 compacted cells
# ── Polygon fill ───────────────────────────────────────────────────
let box = GeoPolygon(
geoloop: @[
LatLng(lat: 37.78, lng: -122.42),
LatLng(lat: 37.78, lng: -122.41),
LatLng(lat: 37.77, lng: -122.41),
LatLng(lat: 37.77, lng: -122.42),
],
holes: @[]
)
for c in polygonToCells(box, 10): # fill polygon with cells
echo c
# ── Directed edges ─────────────────────────────────────────────────
let neighbor = gridRing(cell, 1).value[0]
let edge = cellsToDirectedEdge(cell, neighbor).value
assert edge.directedEdgeOrigin.value == cell
assert edge.reverseDirectedEdge.value.directedEdgeOrigin.value == neighbor
echo edge.directedEdgeToBoundary.value.len # 2
# ── The ? operator for ergonomic error propagation ─────────────────
proc cellWithNeighbors(latLng: LatLng, res: int): Result[seq[H3Cell], H3Error] =
let origin = ?latLngToCell(latLng, res)
let ring = ?gridRing(origin, 1)
ok(@[origin] & ring)
let ring = cellWithNeighbors(sf, 9).valueOr:
echo "failed: ", error
echo ring.len # 7 (origin + 6 neighbors)
Installation
nimble install https://github.com/ayman-albaz/nim-h3
Or in your .nimble file:
requires "h3 >= 0.1.0"
Key Features
- No system library dependencies — H3 v4 C source is embedded in-tree
- Result-based error handling — every fallible operation returns
Result[T, H3Error]; the?operator propagates errors ergonomically - Incremental iterators —
cellToChildrenandres0Cellsuse the C library's native state machines for true zero-allocation streaming; all iterators are safe tobreakout of - Full API coverage — indexing, inspection, traversal, hierarchy, regions, edges, vertexes, and measurement functions
Requirements
- Nim >= 2.0.0
- No system dependencies (all C source is embedded)
License
Apache-2.0 — same as Uber's H3 library.
Development
nimble test
Notes
- LLMs were used to help create this wrapper library.
- All code was reviewed by myself.