The short version
GeoPackage (.gpkg) is an OGC standard that packs many spatial layers — vector and raster — plus their styles and even the QGIS project itself into a single SQLite database file. For QGIS work it is the right default: it removes the shapefile's crippling limits (10-character field names, 2 GB cap, no real dates, one geometry layer per file-set), keeps a multi-layer project in one tidy container, and travels cleanly to another machine. The one thing it is not is a multi-user editing database — SQLite is single-writer, so concurrent team editing still belongs in PostGIS. This guide covers how to use GeoPackage well in QGIS and where its edges are.
Why GeoPackage beats shapefiles
A shapefile is not one file; it is at least .shp, .shx, and .dbf, usually with .prj and .cpg, and losing any of them breaks the dataset. Its .dbf attribute table enforces a 1990s-era format: field names truncated to 10 characters, no native date-time, limited text length, a single character encoding that is easy to get wrong, and a hard 2 GB size limit per component. For a GeMS-style geologic dataset, the field-name truncation alone is fatal — LocationConfidenceMeters becomes LocationCo.
GeoPackage, being a SQLite container governed by the OGC spec, fixes all of this: long field names, full data types including 64-bit integers and date-time, UTF-8 throughout, multiple vector layers and raster tile pyramids in one file, and a built-in R-tree spatial index. Under the hood QGIS reads and writes it through GDAL's GPKG driver, so the same file opens in ArcGIS Pro, ogr2ogr, PostGIS imports, and web pipelines.
Creating and loading in QGIS
The fastest path: in the Browser panel, right-click GeoPackage › New GeoPackage…, or take any loaded layer and Export › Save Features As… › format GeoPackage. To add more layers to an existing file, export into the same .gpkg and give each a distinct Layer name — QGIS appends the layer rather than overwriting the file. Confirm the CRS at export; a GeoPackage can hold layers in different CRSs, but a coherent project usually pins them to one (e.g. a UTM zone such as EPSG:32613).
From the command line the equivalent is ogr2ogr:
ogr2ogr -f GPKG project.gpkg units.shp -nln map_units
ogr2ogr -f GPKG -update project.gpkg faults.shp -nln contacts_faults
The -update flag adds a layer to an existing GeoPackage instead of replacing it, and -nln sets the layer name inside the container.
Storing styles and the project inside the GeoPackage
This is the feature that makes GeoPackage genuinely a project format, not just a data format. After symbolizing a layer, open Layer Properties › Symbology › Style ▾ › Save Style… and choose Save in database (GeoPackage) — QGIS writes the QML/SLD style into a layer_styles table so the layer reopens with its symbology intact, on any machine, without a sidecar .qml.
You can go further and save the whole project into the GeoPackage: Project › Save To › GeoPackage… stores the .qgz inside the file. The result is a single artifact that, when handed to a colleague, opens with every layer, its styling, and the project layout already wired up. This is the cleanest possible handoff for a self-contained QGIS project.
A recommended project structure
GeoPackage removes file sprawl, but it does not create a good data model for you. A structure that holds up:
- Keep raw sources in their own untouched folder (or a separate
_source.gpkg); never edit originals in place. - Put cleaned working layers into the project GeoPackage with names a future user can read (
map_units,contacts_faults,orientation_points), notlayer1,export_final_v3. - Store styles in the database so symbology cannot drift from the data.
- Record CRS and source date in the layer metadata even though everything lives in one file.
- Ship the delivery as: the
.gpkg(data + styles), the project (inside it or as a.qgz), and a short README.
Performance and indexing
For responsive panning and fast spatial queries, ensure each layer has a spatial index. QGIS and the GPKG driver create an R-tree index by default on creation; if a layer was imported without one, Layer Properties › Source › Create Spatial Index (or ogrinfo -sql "SELECT CreateSpatialIndex('map_units','geom')") adds it. After heavy editing, a SQLite VACUUM reclaims space and can shrink a bloated .gpkg substantially.
The single-writer limit
GeoPackage is SQLite, and SQLite is a single-writer database: one process holds a write lock at a time. That is fine for one analyst editing, for sequential edits, and for read-many file delivery. It is the wrong tool for several people editing the same layers at once — for that, move to PostGIS, where row-level locking and transactions support real concurrency. A common and sound pattern is to author and edit in PostGIS, then export a GeoPackage snapshot for delivery, offline field use, or archiving.
Common pitfalls and why they happen
- Treating it like a shapefile and re-exporting the whole file for every change, losing the styles and the multi-layer structure. Use Export into the existing file with distinct layer names instead.
- Concurrent editing by two people, hitting
database is locked. SQLite's single-writer model is the cause; use PostGIS for shared editing. - Styles left as sidecar
.qmlthat get separated from the data in transit. Save the style into the database. - No spatial index after a raw import, so large layers feel sluggish. Create the R-tree index.
- Mixed CRSs silently coexisting in one file and surprising the recipient. Standardize, and document the CRS per layer.
Validation summary
Before delivery, confirm: all working layers are in the .gpkg with readable names; each has a saved in-database style and a spatial index; the CRS is consistent and documented; the project opens cleanly from the file on a second machine; and you VACUUM-ed after heavy edits. Verify the file round-trips by reopening it on a machine that never had the original layers.
Bathyl perspective
We use GeoPackage as the standard QGIS deliverable because one well-named, styled, indexed file is something a recipient can open today and maintain tomorrow — and when a project outgrows single-writer editing, we promote it to PostGIS and keep GeoPackage as the snapshot format. Format choice is part of whether the work survives the handoff.