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