All sections

H3 Compaction And Uncompaction

Losslessly replacing a complete set of sibling cells with their parent, and the exact round-trip property that makes it safe to use for storage and target-count optimization.

exactstableh36 min read

Purpose

Compaction is a lossless rewrite of an H3 cell set: wherever a resolution-r cell's complete set of seven children at resolution r+1 is present in the set, those seven children are replaced by the single parent cell. Uncompaction is the exact inverse: every cell in a (possibly mixed- resolution) set is expanded down to a single stated resolution. Both operations exist for two reasons — reducing the cell count needed to represent a target for storage, transmission, or platform target-count limits, and producing rollup summaries at a coarser resolution without re-deriving them from source geometry.

Compaction

Compaction operates purely on the H3 index hierarchy, not on the geometry the cells represent. Given a cell set, it repeatedly checks: for a candidate parent cell at resolution r, are all seven of its resolution-r+1 children present in the set? If so, remove all seven children and insert the parent. This check cascades upward — a newly inserted parent may itself complete its parent's set of seven, and so on — so a fully compacted set can contain cells from many different resolutions at once, each representing the coarsest complete grouping available in that part of the set. A cell set with no complete sibling groups compacts to itself unchanged; compaction never removes coverage, it only changes how completely-covered regions are indexed.

Compaction is logical, not geometric

"Complete set of seven children" is a statement about the H3 indexing hierarchy, established by cellToChildren / cellToParent, not a statement about the children's polygons tiling the parent's polygon with zero gap or overlap in physical space. The two agree closely in practice but are not defined to be identical — see the containment caveat on mixed H3 resolutions.

Uncompaction

Uncompaction reverses this: every cell in the input, regardless of its current resolution, is expanded via cellToChildren down to the single target resolution requested. A cell already at the target resolution passes through unchanged; a coarser cell is expanded into all of its descendants at that resolution. The output is always a uniform-resolution set, which is why uncompaction is the standard first step before running any per-cell aggregation, area estimate, or comparison against another uniform-resolution set — see mixed H3 resolutions for why skipping this step produces double-counted or incomparable results.

The round-trip property

uncompact(compact(S), r) == S

for any cell set S that is already uniform at resolution r. This is the property that makes compaction safe for storage: compacting a set before writing it and uncompacting it back to the original resolution on read must reproduce the exact original set, cell for cell, with no loss and no drift. This round trip is a tested invariant — property-based tests generate uniform-resolution cell sets (including adversarial ones seeded near pentagons and face-crossing cells), compact them, uncompact back to the original resolution, and assert set equality against the input on every run. An implementation that fails this property is not an acceptable trade-off, it is broken.

The round trip only holds at the original resolution

uncompact(compact(S), r) reproduces S only when r is the resolution S was uniform at before compaction. Uncompacting a compacted set to a coarser resolution than the original discards information (folding fine detail upward loses the finer partition); uncompacting to a finer resolution than the original manufactures cells that were never in the source set. Always uncompact to the resolution the set was compacted from unless the intent is a deliberate resolution change, in which case use normalizeToResolution and treat it as a resolution conversion, not a round trip.

Use cases

Compaction is the standard technique for target-count optimization: many platforms cap the number of discrete geo targets accepted per campaign, and a compacted set expresses the same effective geography in far fewer rows whenever the source geometry contains large, uniformly-covered interior regions (a full county polyfilled at resolution 9 compacts to a small number of resolution-6 or resolution-5 cells for its interior, with only the boundary remaining at finer resolution). It is equally the standard technique for reporting rollups: a delivery report aggregated at resolution 6 can be produced directly by compacting resolution-9 delivery data, rather than re-querying source geometry at the coarser resolution.

Algorithm

import { compact, uncompact } from "@/lib/h3/hierarchy";

// Reduce row count for storage / platform target-count limits.
const compacted = compact(uniformResolution9Cells);

// Recover the exact original set — property-tested round trip.
const restored = uncompact(compacted, { resolution: 9 });
// restored is set-equal to uniformResolution9Cells

The same conversion with the Python bindings (h3-py v4):

import h3

# Reduce row count for storage / platform target-count limits.
compacted = h3.compact_cells(uniform_resolution_9_cells)

# Recover the exact original set — round-trip invariant, not a best effort.
restored = h3.uncompact_cells(compacted, 9)
assert set(restored) == set(uniform_resolution_9_cells)

The tested reference implementation in this knowledge base is the TypeScript in lib/, which asserts this round trip as a property-based test (including adversarial cell sets seeded near pentagons and face-crossing cells) rather than checking it once by hand.

Compaction replaces a full child set with its parent; parent (amber) vs children (green) footprints differ only logically.
Rendered from the tested conversion code · Compaction replaces a full child set with its parent; parent (amber) vs children (green) footprints differ only logically.

Parameters

For compact: none beyond the input cell set — the algorithm always compacts maximally. For uncompact: the target resolution, which must be greater than or equal to the coarsest cell present in the compacted input, or the operation is undefined for any cell coarser than the requested target.

Outputs

compact returns a mixed-resolution cell set, typically substantially smaller in cell count than the input for geometries with large uniform interiors. uncompact returns a uniform-resolution cell set at the requested resolution, set-equal to the pre-compaction input when uncompacted back to the original resolution.

Edge cases

Parent-child duplicates are what a broken or partial compaction leaves behind — a set that replaced some but not all of a sibling group, or that was merged with another set after compaction without re-checking for completed groups, ends up with both a parent and some of its children present simultaneously; hasParentChildDuplicate should be run on any compacted set before it is trusted as fully compacted. Mixed resolutions are the expected, correct output shape of compact itself — the presence of multiple resolutions in a compacted set is not a defect, but it does mean the set must be uncompacted (or otherwise normalized) before any operation that assumes a uniform resolution.

Assumptions and limitations

Compaction assumes the input cell set is already uniform at one resolution; running compact on an already-mixed set (rather than uncompacting first) is only correct if the input is known to already reflect a valid partial compaction — otherwise sibling groups that exist across the mixed boundary may go undetected. Compaction reduces cell count; it does not change the geography represented, and it provides no benefit when the source geometry has no large uniformly-covered interior regions (a thin corridor or a boundary-heavy shape compacts to nearly its original size).

Illustration — compaction shrinks the set, not the footprint

before: 34 cells, all R8
before: 34 cells, all R8
after: 22 cells, mixed R6/R7/R8
after: 22 cells, mixed R6/R7/R8
Edge cases affecting this page
  • - A parent and one of its descendants both present double-count the shared area.
  • - A set mixing resolutions cannot be compared or subtracted without normalization.