Geohash & Spatial Code Maps Best Practices
How to implement geohashes correctly in TypeScript and Rust, how to query and index them at scale, and how to apply them to the "codebase as a navigable 2D map" pattern — projecting code into a plane so geohash prefixes become domain regions you can fly through like Google Maps. Contains 42 rules across 8 categories, prioritised by impact.
When to Apply
Reference these guidelines when:
- Implementing or reviewing a geohash encoder/decoder in TypeScript or Rust (bit interleaving, base32, precision, neighbours)
- Building proximity / radius / bounding-box search on lat/lon data, or storing geohashes as index keys (SQL B-tree, Redis sorted sets)
- Debugging the classic geohash bugs — swapped axes, wrong alphabet, border false negatives, off-by-one cells at high precision
- Projecting a codebase (or any abstract graph) into a 2D plane and geohashing it so prefixes name business domains or features
- Navigating a geohashed dataset like a slippy map: zoom-to-precision, viewport tile loading, level-of-detail aggregation, prefix clustering, deep links
A note on scope
Categories 1–4, 6, and 7 are textbook geohashing, drawn from authoritative sources (the geohash spec, the davetroy/geohash-js neighbour tables, Redis, Elasticsearch). Categories 5 (map-) and 8 (nav-) are a novel synthesis — there is no canonical "geohash your codebase" library, so those rules derive design principles from established techniques (deterministic graph layout, Morton/Z-order keys, slippy-map tiling, software cartography). They are honest about when the pattern is overkill.
Rule Categories by Priority
| Priority |
Category |
Impact |
Prefix |
Rules |
| 1 |
Encoding & Bit Interleaving |
CRITICAL |
enc- |
6 |
| 2 |
Precision & Cell Geometry |
CRITICAL |
prec- |
5 |
| 3 |
Neighbours & Adjacency |
HIGH |
nbr- |
5 |
| 4 |
Proximity & Range Queries |
HIGH |
qry- |
5 |
| 5 |
Codebase-as-Map Spatial Layout |
HIGH |
map- |
7 |
| 6 |
Decoding & Bounding Boxes |
MEDIUM-HIGH |
dec- |
4 |
| 7 |
Spatial Indexing & Storage |
MEDIUM-HIGH |
idx- |
5 |
| 8 |
Navigation & Rendering |
MEDIUM |
nav- |
5 |
Quick Reference
1. Encoding & Bit Interleaving (CRITICAL)
enc-interleave-longitude-first — Interleave longitude on even bits, latitude on odd
enc-base32-alphabet — Use the geohash base32 alphabet, not RFC 4648
enc-integer-morton-encode — Encode to an interleaved 64-bit integer for speed and sortable keys
enc-binary-chop-no-float-drift — Recompute interval midpoints; never accumulate a float step
enc-normalize-input-domain — Clamp latitude, wrap longitude, reject non-finite input
enc-five-bit-char-boundary — Accumulate exactly five bits per character
2. Precision & Cell Geometry (CRITICAL)
prec-choose-from-error-radius — Choose geohash length from the required error radius
prec-cells-are-not-square — Treat cells as rectangles whose aspect flips with length
prec-error-is-half-cell — Report decoded accuracy as half the cell, not the full cell
prec-cells-shrink-toward-poles — Scale longitude metres by cos(latitude)
prec-avoid-mixed-precision — Normalise to one precision before comparing or storing
3. Neighbours & Adjacency (HIGH)
nbr-canonical-lookup-tables — Compute neighbours with the canonical border/neighbour tables
nbr-antimeridian-wrap — Wrap east/west neighbours across the antimeridian
nbr-pole-handling — Return no neighbour past the poles
nbr-integer-level-neighbors — Compute neighbours on the de-interleaved integer
nbr-eight-neighbor-set — Build the full eight-neighbour set for proximity
4. Proximity & Range Queries (HIGH)
qry-search-cell-plus-neighbors — Query the cell plus its eight neighbours, never the prefix alone
qry-precision-from-radius — Match query precision to the search radius
qry-bbox-range-decomposition — Decompose a bounding box into covering geohash ranges
qry-refine-with-haversine — Refine geohash candidates with true distance
qry-expand-precision-when-sparse — Widen the search by dropping a prefix character on sparse cells
5. Codebase-as-Map Spatial Layout (HIGH)
map-deterministic-projection — Project code into 2D from a structural signal, not arbitrary layout
map-stable-coordinates — Make coordinates reproducible and incremental-stable
map-normalize-to-geohash-domain — Normalise the code plane into the geohash lat/lon domain
map-coupling-implies-proximity — Validate that coupled code lands in the same region
map-prefix-as-domain-region — Treat a geohash prefix as a named domain region
map-precision-as-architectural-level — Map prefix length to architectural level
map-persist-coordinate-sidecar — Persist the file-to-geohash assignment as a committed sidecar
6. Decoding & Bounding Boxes (MEDIUM-HIGH)
dec-decode-to-bbox — Decode to a bounding box, then derive the centre
dec-symmetric-interval-reconstruction — Decode by mirroring the encoder's interval halving
dec-avoid-roundtrip-reencode — Keep the original hash; don't decode-then-re-encode
dec-precompute-reverse-alphabet — Decode with a precomputed reverse-alphabet table
7. Spatial Indexing & Storage (MEDIUM-HIGH)
idx-sorted-string-range-scan — Store geohashes as sorted strings for prefix range scans
idx-integer-sortable-key — Use the interleaved integer as a compact sortable key
idx-db-prefix-index — Make prefix queries sargable in Postgres and Redis
idx-range-query-from-covering-set — Execute a box query as range scans over the covering set
idx-trie-hierarchical-bucketing — Aggregate by region with a geohash trie
8. Navigation & Rendering (MEDIUM)
nav-precision-to-zoom-levels — Map geohash precision to zoom levels
nav-level-of-detail-aggregation — Render aggregated prefix buckets when zoomed out
nav-tile-lazy-loading — Load only the geohash cells in the viewport
nav-cluster-by-prefix — Cluster overlapping markers by shared prefix
nav-breadcrumb-prefix-path — Use the geohash prefix as navigation state and deep link
How to Use
Read individual reference files for detailed explanations, code examples, and "when NOT to apply" guidance:
- Section definitions — Category structure and impact levels
- Rule template — Template for adding new rules
Rules cross-link via [[other-rule-slug]]; follow them when a related pattern is referenced. To build a code map end to end, the spine is: map-deterministic-projection → map-normalize-to-geohash-domain → encode (category 1) → map-prefix-as-domain-region → navigate (category 8).
Reference Files
| File |
Description |
| references/_sections.md |
Category definitions and ordering |
| assets/templates/_template.md |
Template for new rules |
| metadata.json |
Version and reference information |
1---2name: geohash-spatial-code-maps3description: Geohash encoding/decoding in TypeScript or Rust — bit interleaving, the base32 alphabet, precision and cell geometry, neighbour/adjacency computation, proximity and bounding-box queries, and geohash-backed spatial indexing. Also covers the "codebase as a navigable 2D map" pattern — projecting a codebase into a coordinate plane, geohashing it so prefixes become business-domain regions, and navigating it like Google Maps (zoom, tiles, level-of-detail, clustering, deep links). Trigger when implementing, reviewing, or debugging geohash work — even when the user does not say "geohash" but the work involves spatial hashing, Morton/Z-order codes, proximity search on lat/lon, or mapping and visualising code structure spatially. Contains 42 impact-ordered rules with TypeScript and Rust examples.4---5# Geohash & Spatial Code Maps Best Practices
6
7How to implement geohashes correctly in TypeScript and Rust, how to query and index them at scale, and how to apply them to the "codebase as a navigable 2D map" pattern — projecting code into a plane so geohash prefixes become domain regions you can fly through like Google Maps. Contains 42 rules across 8 categories, prioritised by impact.
8
9## When to Apply
10
11Reference these guidelines when:
12
13- Implementing or reviewing a geohash encoder/decoder in TypeScript or Rust (bit interleaving, base32, precision, neighbours)
14- Building proximity / radius / bounding-box search on lat/lon data, or storing geohashes as index keys (SQL B-tree, Redis sorted sets)
15- Debugging the classic geohash bugs — swapped axes, wrong alphabet, border false negatives, off-by-one cells at high precision
16- Projecting a codebase (or any abstract graph) into a 2D plane and geohashing it so prefixes name business domains or features
17- Navigating a geohashed dataset like a slippy map: zoom-to-precision, viewport tile loading, level-of-detail aggregation, prefix clustering, deep links
18
19## A note on scope
20
21Categories 1–4, 6, and 7 are textbook geohashing, drawn from authoritative sources (the geohash spec, the `davetroy/geohash-js` neighbour tables, Redis, Elasticsearch). Categories 5 (`map-`) and 8 (`nav-`) are a **novel synthesis** — there is no canonical "geohash your codebase" library, so those rules derive design principles from established techniques (deterministic graph layout, Morton/Z-order keys, slippy-map tiling, software cartography). They are honest about when the pattern is overkill.
22
23## Rule Categories by Priority
24
25| Priority | Category | Impact | Prefix | Rules |
26|----------|----------|--------|--------|-------|
27| 1 | Encoding & Bit Interleaving | CRITICAL | `enc-` | 6 |
28| 2 | Precision & Cell Geometry | CRITICAL | `prec-` | 5 |
29| 3 | Neighbours & Adjacency | HIGH | `nbr-` | 5 |
30| 4 | Proximity & Range Queries | HIGH | `qry-` | 5 |
31| 5 | Codebase-as-Map Spatial Layout | HIGH | `map-` | 7 |
32| 6 | Decoding & Bounding Boxes | MEDIUM-HIGH | `dec-` | 4 |
33| 7 | Spatial Indexing & Storage | MEDIUM-HIGH | `idx-` | 5 |
34| 8 | Navigation & Rendering | MEDIUM | `nav-` | 5 |
35
36## Quick Reference
37
38### 1. Encoding & Bit Interleaving (CRITICAL)
39
40- [`enc-interleave-longitude-first`](references/enc-interleave-longitude-first.md) — Interleave longitude on even bits, latitude on odd
41- [`enc-base32-alphabet`](references/enc-base32-alphabet.md) — Use the geohash base32 alphabet, not RFC 4648
42- [`enc-integer-morton-encode`](references/enc-integer-morton-encode.md) — Encode to an interleaved 64-bit integer for speed and sortable keys
43- [`enc-binary-chop-no-float-drift`](references/enc-binary-chop-no-float-drift.md) — Recompute interval midpoints; never accumulate a float step
44- [`enc-normalize-input-domain`](references/enc-normalize-input-domain.md) — Clamp latitude, wrap longitude, reject non-finite input
45- [`enc-five-bit-char-boundary`](references/enc-five-bit-char-boundary.md) — Accumulate exactly five bits per character
46
47### 2. Precision & Cell Geometry (CRITICAL)
48
49- [`prec-choose-from-error-radius`](references/prec-choose-from-error-radius.md) — Choose geohash length from the required error radius
50- [`prec-cells-are-not-square`](references/prec-cells-are-not-square.md) — Treat cells as rectangles whose aspect flips with length
51- [`prec-error-is-half-cell`](references/prec-error-is-half-cell.md) — Report decoded accuracy as half the cell, not the full cell
52- [`prec-cells-shrink-toward-poles`](references/prec-cells-shrink-toward-poles.md) — Scale longitude metres by cos(latitude)
53- [`prec-avoid-mixed-precision`](references/prec-avoid-mixed-precision.md) — Normalise to one precision before comparing or storing
54
55### 3. Neighbours & Adjacency (HIGH)
56
57- [`nbr-canonical-lookup-tables`](references/nbr-canonical-lookup-tables.md) — Compute neighbours with the canonical border/neighbour tables
58- [`nbr-antimeridian-wrap`](references/nbr-antimeridian-wrap.md) — Wrap east/west neighbours across the antimeridian
59- [`nbr-pole-handling`](references/nbr-pole-handling.md) — Return no neighbour past the poles
60- [`nbr-integer-level-neighbors`](references/nbr-integer-level-neighbors.md) — Compute neighbours on the de-interleaved integer
61- [`nbr-eight-neighbor-set`](references/nbr-eight-neighbor-set.md) — Build the full eight-neighbour set for proximity
62
63### 4. Proximity & Range Queries (HIGH)
64
65- [`qry-search-cell-plus-neighbors`](references/qry-search-cell-plus-neighbors.md) — Query the cell plus its eight neighbours, never the prefix alone
66- [`qry-precision-from-radius`](references/qry-precision-from-radius.md) — Match query precision to the search radius
67- [`qry-bbox-range-decomposition`](references/qry-bbox-range-decomposition.md) — Decompose a bounding box into covering geohash ranges
68- [`qry-refine-with-haversine`](references/qry-refine-with-haversine.md) — Refine geohash candidates with true distance
69- [`qry-expand-precision-when-sparse`](references/qry-expand-precision-when-sparse.md) — Widen the search by dropping a prefix character on sparse cells
70
71### 5. Codebase-as-Map Spatial Layout (HIGH)
72
73- [`map-deterministic-projection`](references/map-deterministic-projection.md) — Project code into 2D from a structural signal, not arbitrary layout
74- [`map-stable-coordinates`](references/map-stable-coordinates.md) — Make coordinates reproducible and incremental-stable
75- [`map-normalize-to-geohash-domain`](references/map-normalize-to-geohash-domain.md) — Normalise the code plane into the geohash lat/lon domain
76- [`map-coupling-implies-proximity`](references/map-coupling-implies-proximity.md) — Validate that coupled code lands in the same region
77- [`map-prefix-as-domain-region`](references/map-prefix-as-domain-region.md) — Treat a geohash prefix as a named domain region
78- [`map-precision-as-architectural-level`](references/map-precision-as-architectural-level.md) — Map prefix length to architectural level
79- [`map-persist-coordinate-sidecar`](references/map-persist-coordinate-sidecar.md) — Persist the file-to-geohash assignment as a committed sidecar
80
81### 6. Decoding & Bounding Boxes (MEDIUM-HIGH)
82
83- [`dec-decode-to-bbox`](references/dec-decode-to-bbox.md) — Decode to a bounding box, then derive the centre
84- [`dec-symmetric-interval-reconstruction`](references/dec-symmetric-interval-reconstruction.md) — Decode by mirroring the encoder's interval halving
85- [`dec-avoid-roundtrip-reencode`](references/dec-avoid-roundtrip-reencode.md) — Keep the original hash; don't decode-then-re-encode
86- [`dec-precompute-reverse-alphabet`](references/dec-precompute-reverse-alphabet.md) — Decode with a precomputed reverse-alphabet table
87
88### 7. Spatial Indexing & Storage (MEDIUM-HIGH)
89
90- [`idx-sorted-string-range-scan`](references/idx-sorted-string-range-scan.md) — Store geohashes as sorted strings for prefix range scans
91- [`idx-integer-sortable-key`](references/idx-integer-sortable-key.md) — Use the interleaved integer as a compact sortable key
92- [`idx-db-prefix-index`](references/idx-db-prefix-index.md) — Make prefix queries sargable in Postgres and Redis
93- [`idx-range-query-from-covering-set`](references/idx-range-query-from-covering-set.md) — Execute a box query as range scans over the covering set
94- [`idx-trie-hierarchical-bucketing`](references/idx-trie-hierarchical-bucketing.md) — Aggregate by region with a geohash trie
95
96### 8. Navigation & Rendering (MEDIUM)
97
98- [`nav-precision-to-zoom-levels`](references/nav-precision-to-zoom-levels.md) — Map geohash precision to zoom levels
99- [`nav-level-of-detail-aggregation`](references/nav-level-of-detail-aggregation.md) — Render aggregated prefix buckets when zoomed out
100- [`nav-tile-lazy-loading`](references/nav-tile-lazy-loading.md) — Load only the geohash cells in the viewport
101- [`nav-cluster-by-prefix`](references/nav-cluster-by-prefix.md) — Cluster overlapping markers by shared prefix
102- [`nav-breadcrumb-prefix-path`](references/nav-breadcrumb-prefix-path.md) — Use the geohash prefix as navigation state and deep link
103
104## How to Use
105
106Read individual reference files for detailed explanations, code examples, and "when NOT to apply" guidance:
107
108- [Section definitions](references/_sections.md) — Category structure and impact levels
109- [Rule template](assets/templates/_template.md) — Template for adding new rules
110
111Rules cross-link via `[[other-rule-slug]]`; follow them when a related pattern is referenced. To build a code map end to end, the spine is: [`map-deterministic-projection`](references/map-deterministic-projection.md) → [`map-normalize-to-geohash-domain`](references/map-normalize-to-geohash-domain.md) → encode (category 1) → [`map-prefix-as-domain-region`](references/map-prefix-as-domain-region.md) → navigate (category 8).
112
113## Reference Files
114
115| File | Description |
116|------|-------------|
117| [references/_sections.md](references/_sections.md) | Category definitions and ordering |
118| [assets/templates/_template.md](assets/templates/_template.md) | Template for new rules |
119| [metadata.json](metadata.json) | Version and reference information |