<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>GIS File Formats on File Format Blog</title>
    <link>https://blog.fileformat.com/tag/gis-file-formats/</link>
    <description>Recent content in GIS File Formats on File Format Blog</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en</language>
    <lastBuildDate>Wed, 04 Nov 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://blog.fileformat.com/tag/gis-file-formats/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>GeoParquet vs. GeoJSON - Performance, File Size, &amp; Cloud-Native GIS Compared</title>
      <link>https://blog.fileformat.com/gis/geoparquet-vs-geojson-which-gis-format-is-best-for-large-datasets/</link>
      <pubDate>Wed, 04 Nov 2026 00:00:00 +0000</pubDate>
      
      <guid>https://blog.fileformat.com/gis/geoparquet-vs-geojson-which-gis-format-is-best-for-large-datasets/</guid>
      <description>Torn between GeoParquet and GeoJSON? Learn how file size, query speed, column-level encoding, and cloud storage compare when managing massive GIS datasets.</description>
      <content:encoded><![CDATA[<p><strong>Last Updated</strong>: 2026-11-04</p>
<figure class="align-center ">
    <img loading="lazy" src="images/geoparquet-vs-geojson-which-gis-format-is-best-for-large-datasets.png#center"
         alt="GeoParquet vs. GeoJSON: Which GIS Format Is Best for Large Datasets?"/> 
</figure>

<h2 id="geoparquet-vs-geojson-which-gis-format-is-better-for-large-datasets">GeoParquet vs. GeoJSON: Which GIS Format Is Better for Large Datasets?</h2>
<p>If you have ever tried opening a 2 GB GeoJSON file in QGIS or loading a multi-million-row polygon boundary file into an interactive map, you already know the sinking feeling of a frozen screen and an out-of-memory crash.</p>
<p>For more than a decade, <strong>GeoJSON</strong> has served as the universal lingua franca of web cartography. It is transparent, human-readable, and supported out-of-the-box by nearly every web mapping library and REST API on the internet.</p>
<p>However, modern GIS workflows look radically different than they did in 2008. Today&rsquo;s geospatial practitioners routinely ingest gigabytes (or terabytes) of IoT mobility telemetry, nationwide building footprints, satellite-derived segmentation masks, and high-frequency climate grids.</p>
<p>When applied to datasets at this scale, GeoJSON does not just slow down—it completely bottlenecks data architectures.</p>
<p>Enter <strong>GeoParquet</strong>, an open, standardized geospatial extension to Apache Parquet incubating within the Open Geospatial Consortium (OGC).</p>
<p>In this comprehensive guide, we compare GeoParquet and GeoJSON across architecture, storage efficiency, read/write throughput, cloud readiness, and developer ergonomics to answer a critical question: <strong>Which format should you choose for large datasets?</strong></p>
<hr>
<h2 id="1-structural-architecture-text-vs-binary-columnar">1. Structural Architecture: Text vs. Binary Columnar</h2>
<p>To understand why these formats perform so differently at scale, you have to look under the hood at how each represents coordinate values and tabular metadata.</p>
<pre tabindex="0"><code>+--------------------------------------------------------------+
|                          GeoJSON                             |
|  - Text-based JSON (UTF-8)                                   |
|  - Row-oriented array of feature objects                     |
|  - Plain-text coordinate arrays (e.g., &#34;[ -122.41, 37.77 ]&#34;)  |
|  - Requires full document parse to read one property         |
+--------------------------------------------------------------+
                               VS
+--------------------------------------------------------------+
|                        GeoParquet                            |
|  - Binary columnar storage (Apache Parquet)                  |
|  - Dictionary, RLE, and Snappy/Zstd compression              |
|  - Geometries encoded as WKB (Well-Known Binary)             |
|  - Supports column projection and row-group pushdown         |
+--------------------------------------------------------------+
</code></pre><h3 id="geojson-row-oriented-text-encoded-json">GeoJSON: Row-Oriented, Text-Encoded JSON</h3>
<p>GeoJSON represents data as an array of JSON objects. Every single feature explicitly repeats attribute keys alongside an array of string-encoded floating-point numbers:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">&#34;type&#34;</span>: <span style="color:#e6db74">&#34;FeatureCollection&#34;</span>,
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">&#34;features&#34;</span>: [
</span></span><span style="display:flex;"><span>    {
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">&#34;type&#34;</span>: <span style="color:#e6db74">&#34;Feature&#34;</span>,
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">&#34;properties&#34;</span>: { <span style="color:#f92672">&#34;county&#34;</span>: <span style="color:#e6db74">&#34;Travis&#34;</span>, <span style="color:#f92672">&#34;state&#34;</span>: <span style="color:#e6db74">&#34;TX&#34;</span>, <span style="color:#f92672">&#34;pop_density&#34;</span>: <span style="color:#ae81ff">1845.2</span> },
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">&#34;geometry&#34;</span>: {
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&#34;type&#34;</span>: <span style="color:#e6db74">&#34;Point&#34;</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&#34;coordinates&#34;</span>: [<span style="color:#ae81ff">-97.74306</span>, <span style="color:#ae81ff">30.26715</span>]
</span></span><span style="display:flex;"><span>      }
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>  ]
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>Because GeoJSON is text-based:</p>
<ul>
<li><strong>Repetitive Schemas:</strong> Field names like <code>&quot;properties&quot;</code>, <code>&quot;type&quot;</code>, and <code>&quot;coordinates&quot;</code> are repeated millions of times, bloating the raw file size.</li>
<li><strong>Costly String-to-Float Conversion:</strong> Your CPU must parse text characters (<code>&quot;-&quot;, &quot;9&quot;, &quot;7&quot;, &quot;.&quot;, &quot;7&quot;...</code>) into 64-bit IEEE double-precision floats before performing any spatial operation.</li>
<li><strong>Monolithic Read Requirements:</strong> Standard JSON parsers must ingest the entire file into memory to construct the Document Object Model (DOM). Reading one attribute requires parsing every single feature.</li>
</ul>
<h3 id="geoparquet-column-oriented-binary-encoded-data">GeoParquet: Column-Oriented, Binary-Encoded Data</h3>
<p>GeoParquet builds directly on <strong>Apache Parquet</strong>, storing spatial tables column-by-column rather than row-by-row.</p>
<p>Attributes like <code>county</code> are stored in contiguous blocks, allowing advanced compression techniques such as run-length encoding (RLE), bit-packing, and dictionary compression. Geometry data is standardized as <strong>Well-Known Binary (WKB)</strong>, accompanied by embedded JSON metadata detailing spatial reference systems (CRS), bounding boxes, and geometry types.</p>
<p>Because GeoParquet is binary and columnar:</p>
<ul>
<li><strong>Zero Coordinate Parsing Cost:</strong> Geometries are stored directly in binary form, bypassing expensive string-to-float conversions.</li>
<li><strong>Projection Pushdown:</strong> If your downstream workflow only needs the <code>county</code> and <code>pop_density</code> columns, the reader fetches <em>only</em> those byte offsets from disk or S3, completely skipping the geometry column.</li>
<li><strong>Row-Group Partitioning:</strong> Parquet files split records into self-contained &ldquo;Row Groups&rdquo; (often 100,000 to 1,000,000 rows each) complete with min/max statistics for every column.</li>
</ul>
<hr>
<h2 id="2-head-to-head-comparison-the-core-metrics">2. Head-to-Head Comparison: The Core Metrics</h2>
<table>
<thead>
<tr>
<th style="text-align:left">Evaluation Metric</th>
<th style="text-align:left">GeoJSON</th>
<th style="text-align:left">GeoParquet</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left"><strong>Data Format</strong></td>
<td style="text-align:left">Plain-text JSON (UTF-8)</td>
<td style="text-align:left">Binary columnar (Apache Parquet)</td>
</tr>
<tr>
<td style="text-align:left"><strong>Geometry Representation</strong></td>
<td style="text-align:left">Nested arrays of coordinate strings</td>
<td style="text-align:left">Standardized Well-Known Binary (WKB)</td>
</tr>
<tr>
<td style="text-align:left"><strong>Compression Ratio</strong></td>
<td style="text-align:left">Poor (requires gzip/bzip2 to reduce)</td>
<td style="text-align:left">Exceptional (native Zstd, Snappy, Gzip)</td>
</tr>
<tr>
<td style="text-align:left"><strong>Column Projection</strong></td>
<td style="text-align:left">❌ No (entire record must be parsed)</td>
<td style="text-align:left">✅ Yes (fetch only the columns you need)</td>
</tr>
<tr>
<td style="text-align:left"><strong>Spatial Predicate Pushdown</strong></td>
<td style="text-align:left">❌ No (requires full scan)</td>
<td style="text-align:left">✅ Yes (using bounding box metadata)</td>
</tr>
<tr>
<td style="text-align:left"><strong>Cloud Object Storage (S3/GCS)</strong></td>
<td style="text-align:left">❌ Poor (must download full file)</td>
<td style="text-align:left">✅ Cloud-native (supports HTTP range requests)</td>
</tr>
<tr>
<td style="text-align:left"><strong>Human Readability</strong></td>
<td style="text-align:left">✅ Direct viewing in text editors</td>
<td style="text-align:left">❌ Requires CLI, GIS app, or code</td>
</tr>
<tr>
<td style="text-align:left"><strong>Web Browser Support</strong></td>
<td style="text-align:left">Native JavaScript (<code>JSON.parse</code>)</td>
<td style="text-align:left">Requires WebAssembly (e.g., <code>duckdb-wasm</code>, <code>parquet-wasm</code>)</td>
</tr>
<tr>
<td style="text-align:left"><strong>Standardization Body</strong></td>
<td style="text-align:left">IETF (RFC 7946)</td>
<td style="text-align:left">OGC (Open Geospatial Consortium standard)</td>
</tr>
</tbody>
</table>
<hr>
<h2 id="3-storage-efficiency-and-file-size-benchmarks">3. Storage Efficiency and File Size Benchmarks</h2>
<p>When scaling from thousands to millions of records, storage disparities widen dramatically.</p>
<p>In standard benchmarks using real-world open spatial records (such as OpenStreetMap building footprints, US Census TIGER boundaries, and global ship AIS logs), GeoParquet routinely achieves <strong>70% to 85% storage reductions</strong> compared to raw GeoJSON, and beats <code>.geojson.gz</code> by an additional <strong>20% to 40%</strong>.</p>
<h3 id="why-is-geoparquet-so-much-smaller">Why is GeoParquet so much smaller?</h3>
<ol>
<li><strong>Dictionary Encoding:</strong> Repeated string attributes (e.g., state codes, land-use classifications) are indexed into tiny integer pointers rather than stored repeatedly as long strings.</li>
<li><strong>Compact Binary Coordinates:</strong> A 2D point in GeoJSON takes around 30 to 45 bytes of ASCII text (<code>[-122.4194155, 37.7749295]</code>). In WKB, that same coordinate pair requires exactly 16 bytes.</li>
<li><strong>Modern Compression Algorithms:</strong> Zstandard (<code>Zstd</code>) and Snappy compress columnar byte arrays much more effectively than standard Gzip can compress interleaved row-based text.</li>
</ol>
<hr>
<h2 id="4-query-performance-and-cloud-native-workflows">4. Query Performance and Cloud-Native Workflows</h2>
<p>The biggest differentiator for large datasets is not just storage—it is <strong>query latency and memory utilization</strong>.</p>
<h3 id="1-selective-reads-via-column-projection">1. Selective Reads via Column Projection</h3>
<p>Imagine a 15 GB national parcel dataset containing 60 attributes (owner names, tax IDs, deed history, zoning codes, and complex multipolygon boundaries).</p>
<ul>
<li><strong>In GeoJSON:</strong> If you want to compute the average assessed property value per zip code, your analytical engine has to download and parse all 15 GB, including millions of complex boundary vertices.</li>
<li><strong>In GeoParquet:</strong> Analytical engines like DuckDB, Apache Sedona, Polars, or AWS Athena read <strong>only</strong> the <code>zip_code</code> and <code>assessed_value</code> columns. Instead of transferring 15 GB, your engine downloads and scans less than 80 MB.</li>
</ul>
<h3 id="2-http-range-requests-on-cloud-storage">2. HTTP Range Requests on Cloud Storage</h3>
<p>GeoParquet operates seamlessly as a <strong>cloud-native geospatial format</strong>.</p>
<p>Because Parquet files store internal offsets and metadata in their file footer, client libraries can issue HTTP <code>GET Range: bytes=...</code> requests to cloud object stores like Amazon S3, Google Cloud Storage, or Azure Blob Storage. Rather than downloading an entire multi-gigabyte file, the client reads the footer, identifies the exact byte offsets where relevant records live, and downloads only the required subsets.</p>
<pre tabindex="0"><code>Client (DuckDB / Python / QGIS)
       │
       ├── 1. Read footer metadata (HTTP Range Request) ───► Cloud Storage (S3 / GCS)
       │                                                              │
       ◄── 2. Returns column offsets &amp; row-group stats ───────────────┘
       │
       ├── 3. Read ONLY requested column chunks &amp; ranges ─────────────►
       │                                                              │
       ◄── 4. Fast binary stream (minimal I/O &amp; egress) ──────────────┘
</code></pre><hr>
<h2 id="5-software-ecosystem--tooling-support">5. Software Ecosystem &amp; Tooling Support</h2>
<p>Historically, GeoJSON’s primary advantage was universal tooling support. While that remains true for browser environments, GeoParquet&rsquo;s ecosystem has matured rapidly:</p>
<ul>
<li><strong>Desktop GIS:</strong> Native read/write support in <strong>QGIS 3.28+</strong>, ArcGIS Pro, and GDAL/OGR 3.5+.</li>
<li><strong>Analytical Engines &amp; Languages:</strong> Fast vectorized read/write capabilities across Python (<code>GeoPandas</code>, <code>pyarrow</code>), R (<code>sf</code>), DuckDB (via the spatial extension), Apache Sedona, and Snowflake.</li>
<li><strong>Big Data Pipelines:</strong> Native integration across Apache Spark, Trino, Presto, and Databricks.</li>
<li><strong>Client-Side Web Maps:</strong> Lightweight WebAssembly libraries (such as <code>parquet-wasm</code> and <code>duckdb-wasm</code>) now allow web browsers to query GeoParquet files directly on client devices without a dedicated GIS middleware server.</li>
</ul>
<hr>
<h2 id="6-practical-decision-matrix-when-to-use-which">6. Practical Decision Matrix: When to Use Which?</h2>
<pre tabindex="0"><code>                                Dataset Size &amp; Use Case
                                           │
             ┌─────────────────────────────┴─────────────────────────────┐
             ▼                                                           ▼
     Under 50–100 MB                                              Over 100 MB
(API payloads, simple maps)                                (Data warehousing, big data)
             │                                                           │
             ▼                                                           ▼
      Use **GeoJSON**                                            Use **GeoParquet**
• Direct Mapbox/Leaflet integration                        • High compression ratios
• Human-readable inspection                                • Sub-second analytical queries
• Standard REST API responses                              • Direct S3/GCS HTTP range reads
</code></pre><h3 id="choose-geojson-if">Choose GeoJSON If:</h3>
<ul>
<li>Your dataset is under 50 MB to 100 MB.</li>
<li>You are returning lightweight payload responses from a REST API to frontend clients.</li>
<li>You are building lightweight web maps using Leaflet, MapLibre, or Mapbox GL JS without intermediate translation layers.</li>
<li>You require rapid manual editing or inspection in a standard code or text editor.</li>
</ul>
<h3 id="choose-geoparquet-if">Choose GeoParquet If:</h3>
<ul>
<li>Your dataset exceeds 100 MB, or contains hundreds of thousands of complex spatial features.</li>
<li>You are storing vector assets in cloud object storage (S3, GCS, MinIO, Azure Blob).</li>
<li>You run spatial SQL analytics, feature engineering, or machine learning pipelines using Python, DuckDB, Spark, or Databricks.</li>
<li>You want to reduce storage costs, avoid network egress fees, and eliminate memory crashes.</li>
</ul>
<hr>
<h2 id="7-migration-example-converting-geojson-to-geoparquet">7. Migration Example: Converting GeoJSON to GeoParquet</h2>
<p>Converting existing spatial assets to GeoParquet takes just a few lines of code.</p>
<h3 id="using-python-geopandas">Using Python (GeoPandas)</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#f92672">import</span> geopandas <span style="color:#66d9ef">as</span> gpd
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># 1. Read the legacy GeoJSON file</span>
</span></span><span style="display:flex;"><span>gdf <span style="color:#f92672">=</span> gpd<span style="color:#f92672">.</span>read_file(<span style="color:#e6db74">&#34;large_boundaries.geojson&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># 2. Write directly to GeoParquet using modern Zstandard compression</span>
</span></span><span style="display:flex;"><span>gdf<span style="color:#f92672">.</span>to_parquet(<span style="color:#e6db74">&#34;large_boundaries.parquet&#34;</span>, compression<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;zstd&#34;</span>)
</span></span></code></pre></div><h3 id="using-gdal--ogr-cli">Using GDAL / OGR (CLI)</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>ogr2ogr -f Parquet <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>  -oo LCO:COMPRESSION<span style="color:#f92672">=</span>ZSTD <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>  large_boundaries.parquet <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>  large_boundaries.geojson
</span></span></code></pre></div><h3 id="using-duckdb">Using DuckDB</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sql" data-lang="sql"><span style="display:flex;"><span>INSTALL spatial;
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">LOAD</span> spatial;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- Direct convert via SQL
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">COPY</span> (
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">SELECT</span> <span style="color:#f92672">*</span> <span style="color:#66d9ef">FROM</span> ST_Read(<span style="color:#e6db74">&#39;large_boundaries.geojson&#39;</span>)
</span></span><span style="display:flex;"><span>) <span style="color:#66d9ef">TO</span> <span style="color:#e6db74">&#39;large_boundaries.parquet&#39;</span> 
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">WITH</span> (FORMAT PARQUET, COMPRESSION <span style="color:#e6db74">&#39;ZSTD&#39;</span>);
</span></span></code></pre></div><hr>
<h2 id="8-summary-the-verdict-on-large-datasets">8. Summary: The Verdict on Large Datasets</h2>
<p>For small datasets and direct web endpoints, GeoJSON remains a reliable, hassle-free utility format.</p>
<p>However, <strong>for large datasets, GeoParquet is objectively superior in every operational category</strong>. It delivers smaller file footprints, significantly lower storage overhead, near-instant spatial reads, and native integration with modern cloud data warehouses.</p>
<p>If your geospatial pipelines are groaning under the weight of oversized GeoJSON files, switching to GeoParquet is one of the most effective infrastructure upgrades you can make.</p>
<hr>
<h2 id="frequently-asked-questions-faq">Frequently Asked Questions (FAQ)</h2>
<p><strong>Q1. Is GeoParquet an officially recognized GIS standard?</strong><br>
Yes, GeoParquet is an official open standard maintained under the guidance of the Open Geospatial Consortium (OGC).</p>
<p><strong>Q2. Can I render a GeoParquet file directly in web mapping libraries like Leaflet or Mapbox GL JS?</strong><br>
While not natively parsed like GeoJSON, you can render GeoParquet in browsers using WebAssembly packages like <code>parquet-wasm</code> or by converting files to Vector Tiles (PMTiles/MVT) on ingestion.</p>
<p><strong>Q3. Does GeoParquet support multiple coordinate reference systems (CRS)?</strong><br>
Yes, unlike GeoJSON (which is strictly restricted to WGS 84 / EPSG:4326 by RFC 7946), GeoParquet allows custom CRS definitions directly inside its embedded file metadata.</p>
<p><strong>Q4. How does GeoParquet compare to FlatGeobuf for large spatial datasets?</strong><br>
FlatGeobuf is optimized for streaming spatial features directly to interactive web maps using R-Tree spatial indexing, whereas GeoParquet is designed for high-performance columnar analytics, compression, and massive data lake warehousing.</p>
<p><strong>Q5. Can I open GeoParquet files inside desktop GIS software like QGIS?</strong><br>
Yes, modern versions of QGIS (version 3.28 and above) support dragging, dropping, viewing, and styling GeoParquet files without requiring third-party plugins.</p>
<h2 id="see-also">See Also</h2>
<p><a href="https://blog.fileformat.com/gis/gis-file-formats-at-fileformat-com/"><strong>GIS File Formats at FileFormat.com</strong></a></p>
<p><a href="https://blog.fileformat.com/gis/gis-file-formats-at-fileformat-com/"><strong>Top 5 GIS File Formats for Google Maps</strong></a></p>
<p><a href="https://news.fileformat.com/t/GIS"><strong>File Format News</strong></a></p>
<p><a href="https://forum.fileformat.com/c/gis"><strong>File Format Forums</strong></a></p>
]]></content:encoded>
    </item>
    
  </channel>
</rss>
