GeoParquet vs FlatGeobuf for Cold-Archive Retrieval

Choosing between GeoParquet and FlatGeobuf for a cold spatial archive is a decision about access pattern, not file size: GeoParquet’s columnar layout and per-row-group statistics win analytical scans that touch few columns across many features, while FlatGeobuf’s packed Hilbert R-tree and HTTP range streaming win feature-by-bounding-box reads served straight from object storage. Both are cloud-native, both read anywhere GDAL runs, and both beat legacy shapefiles for archival — but they optimize opposite retrieval shapes, and picking the wrong one turns a penny range request into a multi-gigabyte download. This decision guide is for the data engineers and cloud architects who must commit an archive to one format per access tier under the Format Conversion & Pipeline Automation framework, weighing predicate pushdown, index structure, compression, and tooling against how each dataset is actually retrieved.

Framing the Decision

Cold-archive retrieval is dominated by two workloads that pull the format choice in opposite directions. The first is the analytical scan: “sum the burned area across every wildfire polygon in the 2015–2023 archive,” which reads two or three columns from millions of features and never materializes geometry. The second is the point read: “fetch the parcels intersecting this map viewport,” which needs whole features inside a small bounding box and nothing else. A columnar format serves the first for the cost of reading a few column chunks; a spatially indexed feature format serves the second for the cost of an R-tree descent plus a few range requests. The mistake is committing an archive to one format before profiling which workload dominates — or worse, assuming one format can be optimal for both. The tiering logic here mirrors the broader hot/warm/cold tier design for geospatial data: access pattern, not age alone, drives the layout.

Head-to-Head Comparison

The two formats differ on every axis that matters for retrieval economics:

GeoParquet versus FlatGeobuf retrieval comparison matrix An eight-row matrix comparing GeoParquet and FlatGeobuf across physical layout, spatial index, best access pattern, compression, HTTP range read granularity, predicate pushdown, partial column read, and tooling. GeoParquet leads on analytical and columnar dimensions; FlatGeobuf leads on per-feature spatial reads and streaming. Dimension GeoParquet FlatGeobuf Physical layout columnar (Parquet) row-oriented per feature Spatial index row-group bbox stats packed Hilbert R-tree Best access pattern analytical column scans feature-by-bbox reads Compression strong per-column ZSTD lighter, packed geometry HTTP range read row-group granularity per-feature streaming Predicate pushdown strong (column + stats) spatial bbox only Partial column read yes (projection) no (whole feature) Tooling DuckDB · Arrow · GDAL GDAL · web mapping libs

Per-Dimension Analysis

Physical layout and partial reads

GeoParquet stores each attribute in its own contiguous column chunk, so a query that needs burn_area_ha and fire_year reads exactly those two chunks and skips the geometry entirely. That projection is impossible in FlatGeobuf, where every feature is a self-contained record: reading one attribute means paging in the whole feature, geometry included. For an analytical scan over a wide attribute table, this is the single largest difference in bytes transferred — often an order of magnitude — because cold-storage cost is dominated by what you move, not what you store. FlatGeobuf’s row orientation is the correct trade only when you genuinely want the whole feature.

Index structure and the point-read path

FlatGeobuf embeds a packed Hilbert R-tree in the file header, laid out so a bounding-box query resolves to a small set of byte ranges without a full scan. A client issues one range request for the index, walks it, then issues range requests for the matching feature bytes — three or four round trips to pull the parcels in a viewport, straight from S3 with no server. GeoParquet’s spatial “index” is coarser: per-row-group bounding-box statistics let a reader skip row groups that cannot intersect the query, but within a surviving row group it still scans. If your row groups are spatially clustered — the payoff of spatial partitioning techniques — this pruning is effective for regional filters, but it will never match FlatGeobuf’s per-feature precision for a tight bbox over a dense layer.

Compression and cold-storage footprint

Columnar storage compresses better because a column is a run of like-typed, often low-cardinality values — exactly what dictionary and ZSTD encoders exploit. A GeoParquet archive of categorical vector data routinely lands well under half the size of the equivalent FlatGeobuf, and the ratio widens as you tune the encoder; the level-versus-latency trade-off is laid out in ZSTD level configuration for spatial files. FlatGeobuf compresses its geometry buffer efficiently but cannot reach columnar ratios on attributes, because each feature interleaves fields of different types. For a deep-archive tier billed purely on stored bytes, GeoParquet’s footprint advantage is decisive; for a warm tier billed on retrieval, footprint matters less than range-read efficiency.

Streaming and serverless retrieval

FlatGeobuf was designed to stream: a reader can begin emitting features before the whole file arrives, and the format is a first-class citizen of browser mapping stacks that fetch directly from object storage over HTTP range requests. That makes it the natural archive format when the retrieval client is a map, not a query engine, and there is no compute layer between the bucket and the user. GeoParquet retrieval assumes a reader that understands row groups and statistics — DuckDB, Arrow, GDAL, or a Spark job — so it shines when a serverless SQL engine sits in front of the archive, and is awkward when the consumer is a thin web client. The optimization details for the streaming path are covered under FlatGeobuf optimization techniques, and the columnar migration path under GeoParquet migration workflows.

Tooling and durability

Both formats are open and GDAL-native, so neither is a lock-in risk. GeoParquet inherits the entire Parquet and Arrow ecosystem — DuckDB, pandas, Spark, cloud query services — which is a large advantage for analytical archives and for interoperability with non-spatial data lakes. FlatGeobuf’s ecosystem is narrower and mapping-centric, but its specification is simpler, which some archivists weigh as a durability argument for a format that must remain readable for decades. Both are backed by public specifications; verify writer conformance against the GeoParquet specification and the FlatGeobuf specification before committing an archive.

Recommendation by Scenario

Analytical archive queried by SQL — choose GeoParquet. When the dominant workload is aggregations, filters, and joins across many features touching few columns — climate model outputs, census-scale demographics, sensor time series — the columnar layout and predicate pushdown make GeoParquet the clear winner, and its compression minimizes the deep-archive bill.

Web-map archive served straight from object storage — choose FlatGeobuf. When retrieval means “give me the features in this viewport” and the client is a browser hitting a bucket with no query engine in between, FlatGeobuf’s packed R-tree and range streaming deliver sub-second bbox reads that GeoParquet cannot match on a dense layer.

Mixed archive with both patterns — dual-encode by tier. Keep the authoritative copy as partitioned GeoParquet in the cold, cost-optimized tier for analytics and long-term preservation, and derive a FlatGeobuf copy into a warm, retrieval-optimized tier for the map-serving path. The GeoParquet partition boundary maps cleanly onto the FlatGeobuf tiles, so the derivation is deterministic, and each tier’s storage class is chosen against its real access economics rather than a single compromise.

Uncertain or evolving access pattern — default to GeoParquet. Its broader tooling and superior compression make it the safer default when you cannot yet profile the workload; a FlatGeobuf derivative can always be generated later from the columnar master, whereas reconstructing columnar statistics from FlatGeobuf is a full rewrite.

Before committing either choice at scale, model the retrieval side — request counts, egress, and restore fees — with spatial archive cost modeling, because for cold data the retrieval bill, not the storage bill, usually decides the winner.

Validating the Choice on Real Data

Before standardizing a format, benchmark both against a representative sample and measure bytes transferred, not just wall-clock time. Encode the same layer each way, then run each format’s characteristic query directly against object storage:

# GeoParquet: analytical scan touching two columns, projection pushdown
duckdb -c "
  INSTALL httpfs; LOAD httpfs; INSTALL spatial; LOAD spatial;
  SELECT fire_year, sum(burn_area_ha) AS total_ha
  FROM read_parquet('s3://spatial-archive/fire/geoparquet/**/*.parquet')
  GROUP BY fire_year ORDER BY fire_year;"

# FlatGeobuf: bounding-box feature read, R-tree range requests only
ogr2ogr -f GPKG /vsimem/viewport.gpkg \
  /vsis3/spatial-archive/fire/fire_perimeters.fgb \
  -spat -122.6 37.7 -122.3 37.9 -progress

Expected shape of the result — the GeoParquet scan returns an aggregate having read only two column chunks, confirming projection pushdown worked:

┌───────────┬───────────┐
│ fire_year │ total_ha  │
├───────────┼───────────┤
│   2015    │  184203.5 │
│   2016    │  201884.1 │
└───────────┴───────────┘

Compare the bytes each retrieval moved — enable request logging on the bucket — and let the transfer volume, weighted by your real query mix, settle the decision.

Troubleshooting Format Selection

Symptom Cause Fix
GeoParquet bbox reads scan far more than expected Row groups are not spatially clustered, so statistics prune poorly Sort by a spatial key and re-write with smaller row groups before archiving
FlatGeobuf analytical scan transfers the whole file Row-oriented layout has no column projection Move analytics to a GeoParquet copy; keep FlatGeobuf only for bbox reads
GeoParquet retrieval needs a running engine users lack Consumers are thin web clients, not query engines Derive a FlatGeobuf tier for direct-from-bucket map serving
Deep-archive bill higher than modeled FlatGeobuf attribute compression trails columnar Store the preservation master as GeoParquet; treat FlatGeobuf as a derived access copy

Operational Execution Checklist

Part of the Spatial Data Archival knowledge base.