Shapefile vs GeoPackage vs GeoJSON: Which One to Use

Short answer: collect and edit in GeoPackage, publish to the web in GeoJSON, and hand over a Shapefile only when the other side insists. The rest is evidence: one dataset converted three ways on 15 September 2026, eight questions asked of each copy, the command behind every answer.

The dataset is IBGE's 2022 mesh of the 27 Brazilian states: 27 polygons, five fields. It arrives as a 13,717,460-byte zip whose SHA-256 is 282ec7f0f0beeeead45e6609f4ffffce161bda04cb8ee0afcad2316d1c841bcb; the directory listing prints no licence line, so credit IBGE and check the portal's terms before republishing.

How the three copies were made

The zip holds five files: BR_UF_2022.shp, .shx, .dbf, .prj and .cpg. ogrinfo -so reports 27 polygons in SIRGAS 2000, which GDAL identifies as EPSG:4674 — not WGS 84, which matters below. The GeoPackage came from ogr2ogr -f GPKG uf.gpkg BR_UF_2022.shp, keeping the CRS. The GeoJSON came from ogr2ogr -f GeoJSON uf.geojson BR_UF_2022.shp -t_srs EPSG:4326 -lco RFC7946=YES, plus a second copy with -lco COORDINATE_PRECISION=6. Only the GeoJSON was reprojected, because RFC 7946 leaves it no choice: a GeoJSON "in SIRGAS 2000" has no way to say so. GDAL 3.13.3 throughout; each loose set was then compressed with zip -9.

The plain GPKG command also warns that a MULTIPOLYGON is being inserted into a layer declared POLYGON: the Shapefile format has one polygon shape type, so multi-part states such as Pará arrive labelled as plain polygons. -nlt MULTIPOLYGON silences it and is the correct declaration.

The eight criteria

Same three bullets, same order, every time. Where it was measured, the number is quoted; where it is a statement about the specification, the lead-in says so.

File size

Loose is the bytes on disk; zipped is the same files after zip -9. The Shapefile's loose size is its five files summed.

  • Shapefile — 18,227,115 bytes loose (17.38 MiB), of which 18,224,100 are the .shp and 2,543 the .dbf; 13,794,222 bytes zipped (13.16 MiB). IBGE's own zip is 13,717,460 bytes — the same five files, a different archive.
  • GeoPackage — 18,386,944 bytes loose (17.54 MiB), 13,828,105 zipped (13.19 MiB). That is 159,829 bytes more than the Shapefile loose and 33,883 more zipped: the SQLite page structure and the spatial index cost more than the .shx they replace. The folk wisdom that GeoPackage saves bytes is not true here.
  • GeoJSON — 29,108,343 bytes loose at the RFC 7946 default of seven decimals (27.76 MiB) and 26,839,688 at six (25.60 MiB); but zipped it is the smallest of the three by about 5 MiB — 8,457,365 bytes (8.07 MiB) and 7,132,808 (6.80 MiB). Text deflates at 71–73 %, binary shapes at 24–25 %. Six decimals is about 0.11 m at the equator, so Acre's first vertex moving from [-68.7928173,-10.9995693] to [-68.792817,-10.999569] is invisible at any zoom.

Field names

The Shapefile's attribute table is a dBase file, and dBase caps a field name at ten characters. The IBGE file never hits that cap — its five fields are CD_UF, NM_UF, SIGLA_UF, NM_REGIAO and AREA_KM2, the longest nine characters — so we induced it: a 26-character alias, -sql "SELECT *, NM_UF AS nome_da_unidade_federativa FROM BR_UF_2022", written to each format.

  • Shapefile — GDAL printed Warning 6: Normalized/laundered field name: 'nome_da_unidade_federativa' to 'nome_da_un' and the table came out with a column called nome_da_un. An alias of exactly ten characters drew no warning, so it is the length and nothing else.
  • GeoPackagenome_da_unidade_federativa survived intact; sqlite3 lists it as a TEXT(50) column.
  • GeoJSONnome_da_unidade_federativa survived too, as a property key on each of the 27 states. A property name is a JSON string, as long as you like.

Encoding

A Shapefile's text lives in the .dbf, and this file's .dbf header declares no codepage (its language-driver byte is 0). The only place it says UTF-8 is the five-byte .cpg sidecar, whose entire content is UTF-8. We removed it and asked for the state names again.

  • Shapefile — with the .cpg present GDAL reports ENCODING_FROM_CPG=UTF-8 and prints Pará, Amapá and Maranhão correctly. With it gone, GDAL reports an empty source encoding and passes the bytes through, so Amapá still looks right in a UTF-8 terminal — luck, not knowledge. The moment a reader assumes the codepage Shapefiles carried for twenty years, Latin-1 or Windows-1252 (--config SHAPE_ENCODING ISO-8859-1 reproduces it), the same bytes print as Amapá and São Paulo, and the mojibake goes into every file exported from it. No question mark appeared in any run: wrong letters, not missing ones.
  • GeoPackage — UTF-8 by specification; file reads it off the SQLite header, and ogrinfo prints Pará, Amapá and Paraíba with no sidecar to lose.
  • GeoJSON — UTF-8 by specification, because JSON is; grep -c Amapá finds the name in both copies, bytes C3 A1.

CRS carried

Where the file says which coordinate system its numbers are in, and whether with a code a machine can look up.

  • Shapefile — the .prj is 151 bytes of ESRI WKT beginning GEOGCS["GCS_SIRGAS_2000", and grep -c 'AUTHORITY\|EPSG' on it returns 0: no authority code in the file. When ogrinfo prints ID["EPSG",4674] it is GDAL matching the text against its own database, not reading a number. Our EPSG cheat sheet explains why "my file has no EPSG code" is so common a complaint.
  • GeoPackage — the CRS is a row in gpkg_spatial_ref_sys with authority and code, EPSG / 4674, and gpkg_geometry_columns binds the layer to it. Two undefined rows and 4326 sit beside it because the specification requires them.
  • GeoJSON — nothing. grep -c '"crs"' returns 0 on both copies. RFC 7946 §4 fixes the CRS of every GeoJSON to WGS 84, longitude first, which is why the conversion had to reproject — and why a GeoJSON still in SIRGAS 2000 or in UTM metres is drawn in the wrong place with no error. Our GeoJSON guide covers that case.

One file or many

What you have to keep together for the data to open.

  • Shapefile — five files from IBGE: .shp, .shx, .dbf, .prj, .cpg. Three are mandatory for the format to open; the other two carry the CRS and the encoding, and are the ones most often lost. IBGE ships no .sbn/.sbx index and no .shp.xml metadata.
  • GeoPackage — one file, uf.gpkg. SQLite may leave a transient -journal or -wal beside it while writing; none was left here.
  • GeoJSON — one file, uf.geojson.

Size ceiling

A statement from each format's own documentation, not a measurement — the biggest file here is 29 MB.

  • Shapefile — 2 GB per .shp and per .dbf. GDAL's Shapefile driver page puts it as "it is not recommended to use a file size over 2GB for both .SHP and .DBF files" and documents a warning emitted when the limit is reached.
  • GeoPackage — SQLite's limit, which SQLite's own limits page states as "about 281 terabytes". In practice, the disk.
  • GeoJSON — no ceiling in RFC 7946. The practical limit is whatever parses the text in memory: the free viewer below has no byte or feature cap, so the browser's memory decides.

Editability

Also a statement, not a measurement — what an edit costs in each format.

  • Shapefile — editable in place by desktop GIS, but every edit rewrites .shp, .shx and .dbf together, because the .shx is an offset index into the .shp. A field rename is bounded by the ten characters above, a text edit by the codepage.
  • GeoPackage — a SQLite database: edits are transactions with rollback on failure, concurrent readers are safe, and any SQLite client can update an attribute without a GIS. This is where the one file earns back the bytes it cost.
  • GeoJSON — plain text, so any editor changes a property; but there is no index and no transaction, and a 27 MiB file is a 27 MiB rewrite for a one-character change. Fine by hand, wrong for a workflow.

Load time in the free viewers

Measured on the live tools with a headless Chromium at 1280×1000, one fresh browser per run, three runs per file, the local file handed to the page's file input; the clock runs from the hand-over until the layers panel, expanded with one click after the file registers, lists all 27 states — so each number includes that click and its re-render. Read the medians as "about a second and a half" and "about three seconds": one machine, one afternoon.

  • Shapefile — the zip (13,794,222 bytes) dropped on the shapefile-viewer: median 1,621 ms (runs 1,621 / 1,621 / 1,404).
  • GeoPackage — no viewer. tools.geodocs.io has eight viewers and none opens a .gpkg, for the reason the GeoPackage guide gives: a SQLite database needs a SQLite engine. Open it in QGIS.
  • GeoJSON — the seven-decimal file (29,108,343 bytes) dropped on the geojson-viewer: median 3,559 ms (runs 2,770 / 3,559 / 4,735). The six-decimal file's median was 2,740 ms, but its runs spread from 2,435 to 4,158 ms — as wide as the gap between the precisions — so we do not claim six decimals loads faster. Both are roughly twice the zipped Shapefile.

Which one, then

If you collect or edit data — a field team, a survey, an inventory that changes weekly — use GeoPackage. One file, transactions, the CRS stored as a code, UTF-8 without a sidecar, field names as long as the column deserves. It costs 159,829 bytes more than the Shapefile here and buys everything else on this page. Its one gap is the browser: no free viewer, so keep QGIS nearby.

If the destination is the web or an API — a map on a page, a fetch from JavaScript, a payload between services — use GeoJSON. It is the smallest of the three over the wire once compressed, it opens in the free viewer with nothing installed, and every web library reads it. Reproject to WGS 84 first, because the format cannot record anything else, and mind the loose size: 29 MB in a tab is fine, ten times that is a decision.

If the other side insists on a Shapefile, send one — all five files in a zip, and name the encoding and the CRS in the message, because the .cpg and the .prj are the two files that go missing and the two whose absence gives a map that is wrong rather than one that fails. Our Shapefile guide explains each sidecar.

For teams

A format is what you hand over; the workflow is where the time goes. Geodocs is built for the workflow side — field collection with attributes that keep their names and their accents, shared by a team on one map — so the format question only comes up at export, the right moment for it.

Related Articles

Navegação