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
.shpand 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
.shxthey 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 callednome_da_un. An alias of exactly ten characters drew no warning, so it is the length and nothing else. - GeoPackage —
nome_da_unidade_federativasurvived intact;sqlite3lists it as aTEXT(50)column. - GeoJSON —
nome_da_unidade_federativasurvived 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
.cpgpresent GDAL reportsENCODING_FROM_CPG=UTF-8and printsPará,AmapáandMaranhãocorrectly. With it gone, GDAL reports an empty source encoding and passes the bytes through, soAmapá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-1reproduces it), the same bytes print asAmapáandSã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;
filereads it off the SQLite header, andogrinfoprintsPará,AmapáandParaíbawith no sidecar to lose. - GeoJSON — UTF-8 by specification, because JSON is;
grep -c Amapáfinds the name in both copies, bytesC3 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
.prjis 151 bytes of ESRI WKT beginningGEOGCS["GCS_SIRGAS_2000", andgrep -c 'AUTHORITY\|EPSG'on it returns 0: no authority code in the file. WhenogrinfoprintsID["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_syswith authority and code,EPSG/4674, andgpkg_geometry_columnsbinds the layer to it. Two undefined rows and4326sit 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/.sbxindex and no.shp.xmlmetadata. - GeoPackage — one file,
uf.gpkg. SQLite may leave a transient-journalor-walbeside 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
.shpand 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,.shxand.dbftogether, because the.shxis 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.