GeoPackage (.gpkg): La guía definitiva
Alguien te mandó un .gpkg y no sabés qué hacer con él. O tenés una carpeta llena de Shapefiles, ya te dijeron que GeoPackage es "el sustituto moderno", y querés saber si eso es verdad o solo una moda.
Las dos respuestas están abajo, y todo lo que hay de factual en esta página fue probado, no copiado. Construimos GeoPackages y Shapefiles con GDAL 3.13.1 y SQLite 3.53.3, corrimos las conversiones, abrimos los archivos con un cliente SQLite común y leímos los bytes. Cuando una afirmación viene de la especificación de la OGC en lugar de nuestro terminal, lo avisamos. Todo lo que está aquí fue verificado el 14 de julio de 2026.
Una cosa desde el principio, porque la mayoría de los artículos falla en esto: un Shapefile no pierde sus booleanos. Pierde otras cosas — cosas peores — y te vamos a mostrar exactamente cuáles.
El cambio de mentalidad: un GeoPackage es una base SQLite
Eso es, eso es todo. Una vez que cae la ficha, todo lo demás se deduce de ahí.
Un archivo .gpkg es una base de datos SQLite común, con un conjunto estandarizado de tablas definido por la especificación GeoPackage de la OGC. No es un contenedor binario nuevo. No es un zip. Es SQLite, y toda herramienta SQLite del planeta ya sabe abrirlo.
Ejecutá file parcelas.gpkg y te devuelve SQLite 3.x database (OGC GeoPackage file), user version 10400. Leé los primeros dieciséis bytes y son, literalmente, SQLite format 3\0. Lo que lo convierte en un GeoPackage en lugar de una base cualquiera es un application_id de cuatro bytes en el offset 68, que escribe GPKG en ASCII, más un user_version — medimos 10400, es decir, GeoPackage 1.4.
Así que esto funciona, sin ningún software de GIS instalado:
- Ver qué contiene: sqlite3 parcelas.gpkg "SELECT table_name, data_type FROM gpkg_contents;" — gpkg_contents es el registro de capas. El nuestro devolvió parcelas|features, vias|features, hillshade|tiles.
- Consultar tus datos con SQL: sqlite3 parcelas.gpkg "SELECT fid, owner_name FROM parcelas WHERE status = 1;"
- Volcar los atributos a CSV: sqlite3 -header -csv parcelas.gpkg "SELECT owner_name, area_m2 FROM parcelas;"
- Encontrar la columna de geometría: sqlite3 parcelas.gpkg "SELECT table_name, column_name, geometry_type_name, srs_id FROM gpkg_geometry_columns;"
Cuando GDAL escribe un GeoPackage, crea alrededor de catorce tablas. Junto con tu tabla de datos vienen gpkg_contents, gpkg_geometry_columns, gpkg_spatial_ref_sys (las proyecciones, guardadas dentro del archivo — nunca más un .prj perdido), gpkg_extensions, gpkg_metadata, la familia gpkg_tile_matrix para rasters, y un conjunto de tablas rtree_* que son el índice espacial. También instala unos diecinueve triggers para mantener la R-tree y las cuentas de features honestas conforme insertás y borrás.
Esa última parte importa: el índice espacial es una tabla real, viva y consultable. sqlite3 parcelas.gpkg "SELECT id, minx, miny FROM rtree_parcelas_geom WHERE minx > -38.55;" devuelve filas. Tu consulta por bounding box está siendo respondida por una R-tree dentro del archivo, y no por un scan.
Lo que un Shapefile realmente te cuesta
Tomamos un dataset pequeño — parcelas de relevamiento brasileñas, nombres acentuados, un timestamp, un booleano, algunos NULLs — y lo pasamos por los dos formatos. Esto es lo que el Shapefile le hizo.
Trunca los nombres de tus campos a 10 caracteres, en silencio
Este es el famoso, y es peor de lo que la gente recuerda. El formato .dbf limita los nombres de campo a 10 caracteres. Convertí y GDAL avisa, y luego mutila:
- identificacao_do_proprietario se volvió identifica
- area_construida_m2 se volvió area_const
- data_da_vistoria se volvió data_da_vi
- situacao_regular se volvió situacao_r
Y cuando dos nombres colisionan, inventa nombres nuevos. Le dimos observacao_tecnica_inicial y observacao_tecnica_final. Ambos se truncan a observacao, así que GDAL renombró el segundo a observac_1. Tu esquema ahora es trivia posicional. Quien abra ese archivo después tendrá que adivinar cuál de los dos era el "inicial".
Esto es permanente. Nos mordió a mitad de escribir este texto: convertimos un Shapefile a GeoPackage y luego corrimos un filtro SQL en situacao_regular, y SQLite escupió no such column: situacao_regular — porque la ida y vuelta por el .dbf ya había destruido el nombre. Convertir de vuelta a GeoPackage no restaura nada. La información se fue.
No tiene datetime real
Convertí un campo DateTime a Shapefile y GDAL te lo dice claro: Field data_da_vi created as String field, though DateTime requested. El tipo de fecha del .dbf guarda una fecha y nada más — sin hora, sin zona. Entonces tu timestamp se rebaja a un String(29) y cualquier herramienta adelante ahora tiene que parsear texto y rezar. En el GeoPackage, el mismo campo sigue siendo un DateTime de verdad.
No sabe diferenciar NULL de cadena vacía
Esta es la que nadie demuestra, así que lo demostramos. Creamos dos features: una con nota en NULL, otra con nota igual a "".
En el GeoPackage, el SQL devuelve exactamente lo que entró — typeof() reporta null para la primera y text para la segunda. En el Shapefile, las dos vuelven como `(null)`. El .dbf llena campos no definidos con espacios en blanco y no tiene sentinela de NULL, así que "nunca medimos esto" y "medimos y estaba vacío" se vuelven el mismo valor, para siempre. Si hacés QA de datos de campo, esa distinción es todo el trabajo.
El desorden de encoding es real, y el default de GDAL te va a quemar
Aquí está el hallazgo que más nos sorprendió. Convertimos nuestra fuente en UTF-8 a Shapefile con una llamada ogr2ogr simple, sin flags. GDAL no produjo ningún archivo .cpg, y seteo el byte de language driver del .dbf (offset 29) a 87 — que significa Latin-1. Y entonces transcodificó nuestro texto: los bytes crudos en el .dbf contienen Jo\xe3o, la grafía Latin-1 de "João". La secuencia de bytes UTF-8 no está en ninguna parte del archivo.
GDAL lee su propia salida correctamente, porque chequea ese byte. Pero entregá ese Shapefile a cualquier cosa que asuma UTF-8 — lo que en 2026 es casi todo — y "João Conceição" se vuelve mojibake. Es exactamente por eso que datasets en portugués y español llegan con João e MarÃa adentro, y por qué todo equipo de GIS de América Latina tiene una carpeta de tablas de atributos corrompidas.
La corrección, si estás obligado a escribir un Shapefile: ogr2ogr -f "ESRI Shapefile" out_dir input.gpkg -lco ENCODING=UTF-8. Confirmamos que esto escribe un archivo .cpg conteniendo el texto UTF-8, setea el byte de language a 0 y guarda bytes UTF-8 reales.
Leyendo un Shapefile en Latin-1 que otra persona hizo: ogr2ogr -f GPKG out.gpkg in.shp --config SHAPE_ENCODING ISO-8859-1. Corrimos esto contra nuestro propio archivo mutilado y los acentos volvieron intactos.
Un GeoPackage no tiene este problema. SQLite almacena texto como UTF-8. No existe un byte para equivocarse.
Es una pila de archivos, y uno de ellos va a desaparecer
Nuestra conversión produjo cuatro archivos — .shp, .shx, .dbf, .prj — y eso es lo mínimo. En el mundo real, agregá .cpg, .sbn, .sbx, .qix, .qmd. Perdé el .prj y tu capa queda sin proyección. Perdé el .dbf y queda sin atributos. Mandá "el shapefile" por e-mail a un colega y mandaste nada.
Un GeoPackage es un solo archivo. No podés perder la mitad.
Un tipo de geometría por archivo
Un Shapefile guarda puntos, o líneas, o polígonos. No dos de ellos. Una malla vial y sus nodos de cruce son dos archivos, dos capas, dos de cada cosa.
Pusimos una capa de puntos, una de líneas y un raster dentro de un único GeoPackage, y ogrinfo listó todo limpito como 1: parcelas (Point) y 2: vias (Line String), con gpkg_contents también cargando hillshade|tiles. Un archivo, tres capas, tipos mezclados.
El techo de 2 GB — y el default peligroso de GDAL
La especificación del Shapefile guarda el tamaño del archivo como un conteo de palabras de 16 bits en un entero de 32 bits con signo, y de ahí viene el famoso límite práctico de 2 GB (esa parte es spec, no es nuestro terminal).
Lo que nosotros de hecho verificamos es más interesante. El driver de Shapefile de GDAL expone una opción de creación llamada literalmente 2GB_LIMIT, y su valor por defecto es `NO`. Leé de nuevo: por defecto, GDAL va alegremente a escribir un .shp o .dbf mayor que 2 GB — un archivo fuera de la spec, que otros softwares van a rechazar o leer mal. El límite del formato no te protege; solo espera.
El GeoPackage hereda los límites de SQLite, que llegan a la casa de los terabytes. En la práctica, tu paciencia termina mucho antes que el formato.
Lo que el Shapefile no rompe
Credibilidad vale en ambos sentidos, así que: esa historia de que "Shapefile no tiene booleano", que leés en todas partes, está equivocada. El formato .dbf tiene un tipo de campo lógico, y vimos un booleano sobrevivir la ida y vuelta — volvió como Integer(Boolean) con ancho 1, valores 1 y 0, correcto. No migres por ese motivo. Migra por los cuatro de arriba, que son reales.
Los rasters también viven ahí dentro
Casi todo artículo sobre GeoPackage trata el formato como si fuera vectorial. No lo es. gpkg_contents.data_type puede ser features o tiles, y los tiles son una pirámide de verdad.
Empujamos un raster dentro del mismo archivo que ya tenía dos capas vectoriales, con gdal_translate -of GPKG raster.png parcelas.gpkg -co APPEND_SUBDATASET=YES -co RASTER_TABLE=hillshade -a_srs EPSG:4326. Después de eso, ogrinfo parcelas.gpkg reporta Driver: GPKG/GeoPackage y Size is 64, 64, mientras ogrinfo en el mismo archivo sigue listando las capas vectoriales.
Los tiles se almacenan como blobs, una fila por tile, indexados por nivel de zoom, columna y fila. Corrimos SELECT zoom_level, tile_column, tile_row, length(tile_data) FROM hillshade; y obtuvimos 0|0|0|338 bytes, con los magic bytes del blob diciendo 504E47 — hexadecimal para PNG. Es un cache de tiles dentro de una tabla. TILE_FORMAT te deja elegir PNG, JPEG o WEBP.
O sea: un único .gpkg puede llevar la imagen de tu basemap, tus puntos de relevamiento y los polígonos de tus parcelas, y entregás un solo archivo.
Cómo abrir un .gpkg
- QGIS: arrastrá el archivo dentro del canvas. Si tiene varias capas, QGIS pregunta cuáles querés. Es el camino de menor resistencia y es genuinamente bueno.
- Listar las capas por terminal: ogrinfo -so parcelas.gpkg imprime todas las capas y sus tipos de geometría sin cargar los datos.
- Inspeccionar el schema de una capa: ogrinfo -so parcelas.gpkg parcelas te da nombres de campo, tipos y el conteo de features.
- SQLite puro: sqlite3 parcelas.gpkg ".tables" funciona. Cualquier GUI de SQLite también — DB Browser for SQLite, DBeaver, DataGrip. La columna de geometría es un blob con un pequeño encabezado GeoPackage envolviendo WKB estándar.
- Python: geopandas.read_file("parcelas.gpkg", layer="parcelas") es el one-liner. Por debajo es fiona/pyogrio, y ambos aceptan el argumento layer= — lo vas a necesitar, porque un GeoPackage con varias capas no va a adivinar por vos.
- PostGIS: ogr2ogr -f PostgreSQL PG:"dbname=gis" parcelas.gpkg carga todas las capas directo.
Convirtiendo, con comandos que realmente corren
Todos los comandos de esta sección fueron ejecutados contra archivos reales antes de la publicación.
- Shapefile a GeoPackage: ogr2ogr -f GPKG output.gpkg input.shp
- Shapefile a GeoPackage cuando la fuente está en Latin-1 (asumí que está, a menos que haya un .cpg diciendo lo contrario): ogr2ogr -f GPKG output.gpkg input.shp --config SHAPE_ENCODING ISO-8859-1
- GeoPackage a Shapefile, sin destruir los acentos: ogr2ogr -f "ESRI Shapefile" out_dir input.gpkg -lco ENCODING=UTF-8
- Una carpeta entera de Shapefiles dentro de un GeoPackage — corré una vez por archivo, y se acumulan como capas: ogr2ogr -f GPKG combined.gpkg roads.shp -nln roads y después ogr2ogr -f GPKG -update -append combined.gpkg parcels.shp -nln parcels
- Explotar un GeoPackage multicapa de vuelta a un directorio de Shapefiles: ogr2ogr -f "ESRI Shapefile" out_dir input.gpkg — GDAL escribe un Shapefile por capa, y trunca todo nombre de campo con más de 10 caracteres en la salida.
- Reproyectar durante la conversión: ogr2ogr -f GPKG out.gpkg in.gpkg -t_srs EPSG:3857 -nln parcels_3857
- Filtrar con SQL durante la conversión: ogr2ogr -f GPKG regulars.gpkg source.gpkg -sql "SELECT * FROM parcels WHERE status = 1" -nln regulars
- Resolver ese error de geometría single/multi mezclada que QGIS y PostGIS te tiran a la cara: ogr2ogr -f GPKG out.gpkg in.shp -nlt PROMOTE_TO_MULTI
- GeoPackage a GeoJSON para la web — siempre reproyectá a 4326, la spec de GeoJSON lo exige: ogr2ogr -f GeoJSON web.geojson input.gpkg parcels -t_srs EPSG:4326
- GeoPackage a FlatGeobuf: ogr2ogr -f FlatGeobuf out.fgb input.gpkg parcels
El flag -nln nombra la capa de salida. Omitilo y heredás el nombre de la fuente, que es como la gente termina con una capa en producción llamada OGRGeoJSON.
Dónde el GeoPackage es la respuesta equivocada
Si solo te contáramos las partes buenas, deberías dejar de creer el resto de la página.
No lo sirvas a un navegador. Un GeoPackage es un archivo de base de datos. Para leer una feature, el cliente necesita buscar y parsear páginas de la base. No existe una historia de streaming decente sobre HTTP. Para entrega web, usá GeoJSON para capas pequeñas, vector tiles o PMTiles para las grandes, o FlatGeobuf si querés acceso aleatorio con HTTP range requests. Publicar un .gpkg de 400 MB y pedir al navegador que lo descargue antes del primer píxel es dispararte en el pie.
No lo uses como store de escritura multiusuario. SQLite toma un lock de escritura sobre la base entera. Un escritor a la vez, punto. Dos equipos de campo sincronizando en el mismo .gpkg en un compartido de red van a corromper el archivo o van a bloquearse entre sí — y SQLite sobre un sistema de archivos de red como NFS o SMB es explícitamente una mala idea, porque las primitivas de lock de las que depende no son confiables ahí. Si tenés escritores concurrentes, lo que querés es PostGIS. Esto no es una crítica al formato; es un archivo de base de datos, y se comporta como tal.
No presumás que toda herramienta habla el formato. Mucho software municipal y de concesionarias legado todavía solo importa .shp. Algunos paquetes de ingeniería y topografía, algunas instalaciones antiguas de ArcGIS, y más de un portal gubernamental te van a exigir un Shapefile. Cuando eso pase, exportá un Shapefile, aceptá la truncación, y mantené el GeoPackage como tu fuente de la verdad.
No recurras a él para una capa de borrador con cinco features. Si estás pasando tres puntos a un colega, el GeoJSON es legible por humano, hace diff en git, y no necesita ninguna herramienta para comprobar si está bien. No todo necesita una base de datos.
Shapefile vs GeoPackage vs GeoJSON vs FlatGeobuf
Sin tabla — solo elegí lo que corresponda a tu frase.
Andá de GeoPackage cuando los datos son el entregable, o el archivo muerto, o lo que le entregás a un cliente. Muchas capas, tipos de geometría mezclados, rasters junto a vectores, tipos verdaderos, NULLs verdaderos, nombres de campo honestos, un solo archivo. Es el estándar correcto para GIS de escritorio y para datos de campo. Es la respuesta a "acá está el dataset".
Andá de GeoJSON cuando un navegador o una API va a leer el archivo, la capa es pequeña (digamos, algunos MB como máximo), o un humano necesita leer el archivo. Es texto, es universal, hace diff en git. También es verboso, no tiene índice, y está atado a EPSG:4326 por especificación. Es la respuesta a "mandalo al frontend".
Andá de FlatGeobuf cuando tenés un dataset vectorial grande que necesita leerse sobre HTTP sin un servidor de tiles. Es un formato binario, indexado y streamable, y un cliente puede jalar solo las features dentro de una bounding box usando HTTP range requests. Es la respuesta a "capa grande, sin backend".
Andá de vector tiles o PMTiles cuando los usuarios van a hacer pan y zoom sobre un dataset grande en un mapa web. Pre-renderizado, piramidal, cacheado. Es la respuesta a "hacé el mapa rápido".
Andá de Shapefile cuando alguien te obligue. Esa es la lista entera. Es un formato de los años 1990 con un límite de schema de 10 caracteres y un byte de encoding de otra era. Sigue siendo el formato GIS más interoperable del planeta, que es exactamente por qué va a sobrevivir a todos nosotros.
Y si existen escritores concurrentes, ninguno de estos — usá PostGIS.
Trampas que realmente te van a morder
Los archivos-satélite `-wal` y `-shm`. SQLite en modo WAL escribe dos archivos extra al lado de tu base. Abrimos un GeoPackage, empezamos a escribir, y confirmamos que el directorio entonces contenía big.gpkg, big.gpkg-wal y big.gpkg-shm. Después de un cierre limpio, los dos desaparecieron. Pero si un proceso cae — o si copias el .gpkg mientras algo lo tiene abierto — podés capturar un archivo cuyos commits más recientes viven en un -wal que quedó atrás. Cuando hagas backup o envíes un GeoPackage, asegurate de que nada lo tenga abierto, o copialos junto con los archivos-satélite. La promesa de un solo archivo solo vale con el archivo cerrado.
El archivo crece y nunca encoge. SQLite marca las páginas borradas como libres y las reutiliza; no devuelve el espacio al sistema de archivos. Insertamos datos en masa en un GeoPackage hasta que alcanzó 43.335.680 bytes, corrimos DROP TABLE, y el archivo seguía con 43.335.680 bytes — con 10.554 páginas libres sentadas ahí dentro. Entonces corrimos sqlite3 file.gpkg "VACUUM;" y se desplomó a 106.496 bytes. Si andás editando un GeoPackage en QGIS y silenciosamente se volvió gigantesco, ese es el motivo. VACUUM es la respuesta, y es seguro.
ArcGIS antiguo se atraganta con los GeoPackages de GDAL. GDAL 3.13 escribe GeoPackage 1.4 por defecto — leímos el user_version como 10400 y el application_id como la cadena ASCII GPKG. Productos Esri más viejos esperan la era 1.0/1.1, cuyo application_id es GP10 y cuyo user_version es 0. Si ArcMap o un ArcGIS Pro más viejo rechaza tu archivo, generalo de nuevo con ogr2ogr -f GPKG out.gpkg in.gpkg -dsco VERSION=1.0 — corrimos exactamente eso y confirmamos que el application_id vira GP10 y el user_version baja a 0. GDAL acepta 1.0, 1.1, 1.2, 1.3, 1.4 y AUTO.
Nombres de capa son nombres de tabla. El nombre de la capa se vuelve un nombre de tabla SQL, así que una capa llamada 2024 parcels (final) es un problema de comillas para el resto de la vida. Usá minúsculas, underscores, sin espacios, sin dígito al comienzo. Definilo explícitamente con -nln.
El índice espacial no está garantizado. GDAL crea uno por defecto — SPATIAL_INDEX tiene default YES, y contamos 22 objetos rtree_* en un archivo normal de dos capas. Pasale -lco SPATIAL_INDEX=NO y tenés cero. Lo comprobamos. Archivos producidos por otras herramientas, o por alguien optimizando una importación, pueden no tener índice alguno, y entonces toda consulta espacial se vuelve un full scan. Verificá con sqlite3 file.gpkg "SELECT name FROM sqlite_master WHERE name LIKE 'rtree%';" — si viene vacío, ese es tu mapa lento.
No edites los blobs de geometría a mano. La columna de geometría es WKB estándar envuelto en un pequeño encabezado binario del GeoPackage. Escribí en ella con GDAL, QGIS o una extensión espacial de SQLite. No construyas los bytes vos mismo, a menos que te guste depurar geometrías inválidas.
Entonces: ¿deberías migrar?
Sí, para cualquier cosa que sea tuya — con los ojos abiertos.
Mantené el GeoPackage como fuente de la verdad. Exportá un Shapefile cuando un cliente o un portal lo exija, y tratá esa exportación como un render con pérdidas, del mismo modo que tratarías un JPEG de un archivo de diseño en capas. Nunca hagas ida y vuelta por el Shapefile esperando que tu esquema vuelva intacto, porque los nombres de los campos no sobreviven al viaje.
Si tus datos van a un navegador, no deberían ser un GeoPackage para empezar. Convertí a GeoJSON, FlatGeobuf o tiles.
Dónde entra Geodocs
Nosotros construimos Geodocs, una plataforma para equipos de datos de campo y de GIS, y escribimos esta guía porque tratamos con los bordes afilados de este formato todos los días. Nuestros usuarios suben GeoPackages, Shapefiles, KML y GeoJSON, y resolvemos exactamente los problemas arriba para que ellos no tengan que hacerlo — detectando el encoding del .dbf en lugar de adivinar, manteniendo NULL distinto de vacío, y sin truncar el nombre de campo de nadie a diez caracteres.
Si preferís que tu equipo deje de mandar Shapefiles de cuatro archivos por e-mail rezando que el .prj haya llegado junto, es exactamente eso lo que hacemos.
Trabajando en la dirección contraria? Nuestro guía completo del formato Shapefile cubre, con el mismo nivel de detalle, el formato del que estás migrando. Y si solo necesitás mirar un archivo ahora, tenemos un visualizador de Shapefile gratuito, directo en el navegador, que no requiere instalación.
Encontraste un error, o una trampa que dejamos pasar? Hablá con nosotros. Esta página se retesta, no se copia y pega.
Última verificación: 14 de julio de 2026.