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, te dijeron que GeoPackage es "el reemplazo moderno", y querés saber si eso es verdad o es puro cuento.

Las dos respuestas están abajo, y todo lo que se afirma en esta página fue probado, no copiado. Armamos GeoPackages y Shapefiles con GDAL 3.13.1 y SQLite 3.53.3, corrimos las conversiones, abrimos los archivos con un cliente SQLite pelado y leímos los bytes. Cuando una afirmación viene de la especificación OGC y no de nuestra terminal, lo aclaramos. Todo lo de acá se verificó el 14 de julio de 2026.

Una cosa antes de empezar, porque la mayoría de los artículos se equivocan: un Shapefile no te pierde los booleanos. Pierde otras cosas — peores — y te vamos a mostrar exactamente cuáles.

El clic mental: un GeoPackage es una base de datos SQLite

Esto es todo. Una vez que hace clic, el resto se cae de maduro.

Un archivo .gpkg es una base de datos SQLite común y corriente 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 lo puede abrir.

Corré 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 y no en una base de datos cualquiera es un application_id de cuatro bytes en el offset 68, que deletrea GPKG en ASCII, más un user_version — nosotros medimos 10400, o sea GeoPackage 1.4.

Así que esto funciona, sin tener instalado ningún software GIS:

  • Ver qué hay adentro: 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 unas catorce tablas. Junto a tu tabla de datos aparecen gpkg_contents, gpkg_geometry_columns, gpkg_spatial_ref_sys (las proyecciones, guardadas dentro del archivo — se acabaron los .prj perdidos), gpkg_extensions, gpkg_metadata, la familia gpkg_tile_matrix para los rásters, y un conjunto de tablas rtree_* que son el índice espacial. Además instala unos diecinueve triggers para mantener el R-tree y los conteos de entidades honestos a medida que 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 la está respondiendo un R-tree que vive dentro del archivo, no un escaneo.

Lo que un Shapefile realmente te cuesta

Agarramos un dataset chico — parcelas de un relevamiento brasileño, nombres con acentos, 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ís, GDAL avisa, y después destroza (los nombres del ejemplo están en portugués, porque el dataset original lo estaba):

  • identificacao_do_proprietario se convirtió en identifica
  • area_construida_m2 se convirtió en area_const
  • data_da_vistoria se convirtió en data_da_vi
  • situacao_regular se convirtió en situacao_r

Y cuando dos nombres chocan, se inventa otros. Le dimos observacao_tecnica_inicial y observacao_tecnica_final. Los dos truncan a observacao, así que GDAL renombró el segundo a observac_1. Tu esquema ahora es trivia posicional. Cualquiera que lea ese archivo después tiene que adivinar cuál era el "inicial".

Esto es permanente. Nos mordió mientras escribíamos esto: convertimos un Shapefile a GeoPackage y después corrimos un filtro SQL sobre situacao_regular, y SQLite tiró no such column: situacao_regular — porque la ida y vuelta por .dbf ya había destruido el nombre. Convertir de vuelta a GeoPackage no lo restaura. La información se fue.

No tiene un datetime de verdad

Convertí un campo DateTime a Shapefile y GDAL te lo dice sin vueltas: Field data_da_vi created as String field, though DateTime requested. El tipo fecha del .dbf guarda una fecha y nada más — sin hora, sin zona horaria. Así que tu timestamp queda degradado a un String(29) y toda herramienta río abajo ahora tiene que parsear texto y rezar. En el GeoPackage ese mismo campo sigue siendo un DateTime genuino.

No puede distinguir NULL de cadena vacía

Esta es la que nadie demuestra, así que la demostramos nosotros. Creamos dos entidades: una con nota en NULL, otra con nota en "".

A través del GeoPackage, SQL devuelve exactamente lo que entró — typeof() reporta null para la primera y text para la segunda. A través del Shapefile, las dos vuelven como (null). El .dbf rellena los campos sin valor con espacios en blanco y no tiene centinela de NULL, así que "esto nunca lo medimos" y "lo medimos y estaba vacío" pasan a ser el mismo valor para siempre. Si estás haciendo QA sobre datos de campo, esa distinción es todo el trabajo.

El quilombo del encoding es real, y el default de GDAL te va a quemar

Acá está el hallazgo que más nos sorprendió. Convertimos nuestro origen UTF-8 a Shapefile con un ogr2ogr pelado, sin flags. GDAL no produjo ningún archivo .cpg, y puso el byte de language driver del .dbf (offset 29) en 87 — que significa Latin-1. Y después transcodificó nuestro texto: los bytes crudos del .dbf contienen Jo\xe3o, la escritura 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 revisa ese byte. Pero pasale ese Shapefile a cualquier cosa que asuma UTF-8 — que en 2026 es casi todo — y "João Conceição" se convierte en mojibake. Esto es precisamente por lo que los datasets en portugués y en español llegan con João y María adentro, y por lo que todo equipo GIS de América Latina tiene una carpeta con tablas de atributos corrompidas.

La solución, si tenés que escribir un Shapefile sí o sí: ogr2ogr -f "ESRI Shapefile" out_dir input.gpkg -lco ENCODING=UTF-8. Confirmamos que esto escribe un archivo .cpg con el texto UTF-8, pone el byte de idioma en 0, y guarda bytes UTF-8 de verdad.

Leer un Shapefile Latin-1 que hizo otro: ogr2ogr -f GPKG out.gpkg in.shp --config SHAPE_ENCODING ISO-8859-1. Lo corrimos contra nuestro propio archivo destrozado y los acentos volvieron intactos.

Un GeoPackage no tiene ese problema. SQLite guarda el texto como UTF-8. No hay ningún byte que se pueda errar.

Es una pila de archivos, y uno se va a perder

Nuestra conversión produjo cuatro archivos — .shp, .shx, .dbf, .prj — y ese es el mínimo. Sumale .cpg, .sbn, .sbx, .qix, .qmd en el mundo real. Perdé el .prj y tu capa no tiene proyección. Perdé el .dbf y no tiene atributos. Mandale "el shapefile" por mail a un colega y le 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 red vial y sus nodos de intersección son dos archivos, dos capas, dos de todo.

Metimos una capa de puntos, una de líneas y un ráster dentro de un único GeoPackage y ogrinfo las listó prolijamente como 1: parcelas (Point) y 2: vias (Line String), con gpkg_contents llevando además 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 la longitud del archivo como una cuenta de palabras de 16 bits en un entero de 32 bits con signo, que es de donde sale el conocido límite práctico de 2 GB (esta parte es la spec, no nuestra terminal).

Lo que sí verificamos es más interesante. El driver Shapefile de GDAL expone una opción de creación llamada literalmente 2GB_LIMIT, y su default es NO. Leelo de nuevo: por defecto, GDAL te va a escribir tranquilamente un .shp o un .dbf de más de 2 GB — un archivo fuera de spec que otro software va a rechazar o va a leer mal. El límite del formato no te protege; simplemente espera.

GeoPackage hereda en cambio los límites de SQLite, que llegan hasta los terabytes. En la práctica se te va a acabar la paciencia mucho antes que el formato.

Lo que el Shapefile no rompe

La credibilidad corta para los dos lados, así que: la afirmación de que "el Shapefile no tiene booleanos" que vas a leer en todos lados es falsa. 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 esa razón. Migrá por las cuatro de arriba, que sí son reales.

Los rásters también viven ahí adentro

Casi todos los artículos sobre GeoPackage lo tratan como un formato vectorial. No lo es. gpkg_contents.data_type puede ser features o tiles, y los tiles son una pirámide de verdad.

Metimos un ráster en el 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, gdalinfo parcelas.gpkg reporta Driver: GPKG/GeoPackage y Size is 64, 64, mientras que ogrinfo sobre el mismo archivo sigue listando las capas vectoriales.

Los tiles se guardan 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 leyendo 504E47 — hexadecimal para PNG. Es un caché de tiles dentro de una tabla. TILE_FORMAT te deja elegir PNG, JPEG o WEBP.

Así que un solo .gpkg puede llevar tu imagen satelital de fondo, tus puntos de relevamiento y tus polígonos de parcelas, y entregás un solo archivo.

Cómo abrir un .gpkg

  • QGIS: arrastrá el archivo al canvas. Si tiene varias capas, QGIS te pregunta cuáles querés. Es el camino de menor resistencia y está genuinamente bien.
  • Listar las capas desde la terminal: ogrinfo -so parcelas.gpkg imprime cada capa y su tipo de geometría sin cargar los datos.
  • Inspeccionar el esquema de una capa: ogrinfo -so parcelas.gpkg parcelas te da los nombres de campo, los tipos y el conteo de entidades.
  • SQLite pelado: sqlite3 parcelas.gpkg ".tables" funciona. Y 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 los dos aceptan un 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 de una.

Convertir, con comandos que de verdad corren

Cada comando de esta sección se ejecutó contra archivos reales antes de publicar.

  • Shapefile a GeoPackage: ogr2ogr -f GPKG output.gpkg input.shp
  • Shapefile a GeoPackage cuando el origen es Latin-1 (asumí que lo es, salvo que haya un .cpg que diga otra cosa): ogr2ogr -f GPKG output.gpkg input.shp --config SHAPE_ENCODING ISO-8859-1
  • GeoPackage a Shapefile, sin arruinar los acentos: ogr2ogr -f "ESRI Shapefile" out_dir input.gpkg -lco ENCODING=UTF-8
  • Una carpeta entera de Shapefiles dentro de un solo GeoPackage — corré esto una vez por archivo, y se van acumulando 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 todos los nombres de campo de más de 10 caracteres en el camino de salida.
  • Reproyectar mientras convertís: ogr2ogr -f GPKG out.gpkg in.gpkg -t_srs EPSG:3857 -nln parcels_3857
  • Filtrar con SQL mientras convertís: ogr2ogr -f GPKG regulars.gpkg source.gpkg -sql "SELECT * FROM parcels WHERE status = 1" -nln regulars
  • Arreglar el error de geometrías simples/múltiples mezcladas que te tiran QGIS y PostGIS: ogr2ogr -f GPKG out.gpkg in.shp -nlt PROMOTE_TO_MULTI
  • GeoPackage a GeoJSON para la web — reproyectá siempre 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 le pone nombre a la capa de salida. Omitilo y heredás como se llamara el origen, que es la forma en que la gente termina con una capa en producción llamada OGRGeoJSON.

Dónde GeoPackage es la respuesta equivocada

Si solo te contáramos la parte buena, deberías dejar de creerle al resto de la página.

No se lo sirvas a un navegador. Un GeoPackage es un archivo de base de datos. Para leer una sola entidad, un cliente tiene que bajar y parsear páginas de base de datos. No hay ninguna historia de streaming que valga la pena sobre HTTP. Para entrega web usá GeoJSON en capas chicas, vector tiles o PMTiles en las grandes, o FlatGeobuf si querés acceso aleatorio con HTTP range requests. Publicar un .gpkg de 400 MB y pedirle al navegador que lo descargue antes de renderizar el primer píxel es un tiro en el pie.

No lo uses como almacén de escritura multiusuario. SQLite toma un lock de escritura sobre toda la base. Un escritor a la vez, punto. Dos cuadrillas de campo sincronizando contra el mismo .gpkg en una carpeta compartida de red lo van a corromper o se van a bloquear 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 locking de las que depende no son confiables ahí. Si tenés escritores concurrentes, lo que querés es PostGIS. Esto no es un golpe al formato; es un archivo de base de datos, y se comporta como tal.

No asumas que toda herramienta lo habla. Un montón de software municipal y de servicios públicos, ya viejo, todavía importa solo .shp. Algunos paquetes de ingeniería y de topografía, algunas instalaciones antiguas de ArcGIS, y más de un portal de gobierno te van a exigir un Shapefile. Cuando pase, exportá un Shapefile, aceptá la truncación, y mantené el GeoPackage como tu fuente de la verdad.

No lo saques para una capa borrador de cinco entidades. Si le estás pasando tres puntos a un colega, GeoJSON es legible por humanos, diffeable en git, y no necesita ninguna herramienta para revisarlo a ojo. No todo necesita una base de datos.

Shapefile vs GeoPackage vs GeoJSON vs FlatGeobuf

Sin tabla — elegí el que coincida con tu frase.

Agarrá GeoPackage cuando los datos son el entregable, o el archivo histórico, o lo que le entregás a un cliente. Muchas capas, tipos de geometría mezclados, rásters junto a vectores, tipos de verdad, NULLs de verdad, nombres de campo honestos, un solo archivo. Es el default correcto para GIS de escritorio y para datos de campo. Es la respuesta a "acá está el dataset".

Agarrá GeoJSON cuando lo va a leer un navegador o una API, la capa es chica (digamos, menos de unos pocos MB), 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 spec. Es la respuesta a "mandale esto al frontend".

Agarrá FlatGeobuf cuando tenés un dataset vectorial grande que hay que leer sobre HTTP sin un servidor de tiles. Es un formato binario, indexado y streameable, y un cliente puede traerse solo las entidades de un bounding box usando HTTP range requests. Es la respuesta a "capa grande, sin backend".

Agarrá vector tiles o PMTiles cuando los usuarios van a hacer pan y zoom sobre un dataset grande en un mapa web. Pre-renderizado, piramidado, cacheado. Es la respuesta a "hacé que el mapa sea rápido".

Agarrá Shapefile cuando alguien te obliga. Esa es la lista completa. Es un formato de los años 90 con un límite de esquema de 10 caracteres y un byte de encoding de otra era. Sigue siendo el formato GIS más interoperable del planeta, que es justamente por lo que nos va a sobrevivir a todos.

Y si hay escritores concurrentes, ninguno de estos — usá PostGIS.

Para el lado medido de la comparación entre Shapefile, GeoPackage y GeoJSON — tamaños, límites de nombre de campo, encoding, CRS y tiempo de carga en un dataset real — leé Shapefile vs GeoPackage vs GeoJSON: cuál usar.

Trampas que te van a morder de verdad

Los archivos laterales -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 pasó a tener big.gpkg, big.gpkg-wal y big.gpkg-shm. Después de un cierre limpio, los dos desaparecieron. Pero si un proceso se cae — o si copiás el .gpkg mientras algo lo tiene abierto — podés capturar un archivo cuyos commits más recientes viven en un -wal que dejaste atrás. Cuando hagas backup o mandes un GeoPackage, asegurate de que nada lo tenga abierto, o copiá también los archivos laterales. La promesa de "un solo archivo" solo se sostiene cuando el archivo está cerrado.

El archivo crece y nunca se achica. SQLite marca las páginas borradas como libres y las reutiliza; no le devuelve el espacio al sistema de archivos. Insertamos datos en masa en un GeoPackage hasta que llegó a 43.335.680 bytes, corrimos DROP TABLE, y el archivo seguía en 43.335.680 bytes — con 10.554 páginas libres sentadas adentro. Después corrimos sqlite3 file.gpkg "VACUUM;" y colapsó a 106.496 bytes. Si venís editando un GeoPackage en QGIS y se volvió enorme sin que te des cuenta, ese es el motivo. VACUUM es la respuesta, y es segura.

El ArcGIS viejo se atraganta con los GeoPackages de GDAL. GDAL 3.13 escribe GeoPackage 1.4 por defecto — leímos user_version como 10400 y el application_id como la cadena ASCII GPKG. Los productos más viejos de Esri 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 te rechaza el archivo, regeneralo con ogr2ogr -f GPKG out.gpkg in.gpkg -dsco VERSION=1.0 — corrimos exactamente eso y confirmamos que el application_id pasa a GP10 y el user_version cae a 0. GDAL acepta 1.0, 1.1, 1.2, 1.3, 1.4 y AUTO.

Los 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 toda la vida. Usá minúsculas, guiones bajos, sin espacios, sin dígitos al principio. Ponelo explícitamente con -nln.

El índice espacial no está garantizado. GDAL crea uno por defecto — SPATIAL_INDEX viene en YES, y contamos 22 objetos rtree_* en un archivo normal de dos capas. Pasale -lco SPATIAL_INDEX=NO y obtenés cero. Lo chequeamos. Los archivos producidos por otras herramientas, o por alguien optimizando una importación, pueden no tener índice alguno, y entonces cada consulta espacial es un escaneo completo. Verificá con sqlite3 file.gpkg "SELECT name FROM sqlite_master WHERE name LIKE 'rtree%';" — si viene vacío, ahí está 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 de GeoPackage. Escribí ahí con GDAL, con QGIS o con una extensión espacial de SQLite. No armes los bytes vos mismo salvo que te divierta debuggear geometrías inválidas.

Entonces: ¿deberías migrar?

Sí, para todo lo que sea tuyo — con los ojos abiertos.

Mantené el GeoPackage como fuente de la verdad. Exportá un Shapefile cuando un cliente o un portal te lo exija, y tratá esa exportación como un render con pérdida, igual que tratarías un JPEG de un archivo de diseño con capas. Nunca hagas ida y vuelta por Shapefile esperando recuperar tu esquema, porque los nombres de campo no sobreviven el viaje.

Si tus datos van a un navegador, nunca deberían haber sido un GeoPackage. Convertí a GeoJSON, FlatGeobuf o tiles.

Dónde entra Geodocs

Construimos Geodocs, una plataforma para equipos de datos de campo y de GIS, y escribimos esta guía porque lidiamos con los bordes del formato todos los días. Nuestros usuarios suben GeoPackages, Shapefiles, KML y GeoJSON, y nosotros manejamos exactamente los problemas de arriba para que ellos no tengan que hacerlo — detectando el encoding del .dbf en lugar de adivinarlo, manteniendo NULL distinto de vacío, y no truncándole los nombres de campo a diez caracteres a nadie.

Si preferís que tu equipo deje de mandarse Shapefiles de cuatro archivos por mail rezando para que el .prj haya llegado, eso es lo que hacemos.

¿Vas en la dirección contraria? Nuestra guía completa del formato Shapefile cubre con el mismo nivel de detalle el formato del que te estás yendo. Y si lo único que necesitás es mirar un archivo ahora mismo, tenemos un visor de Shapefiles gratuito y en el navegador que no requiere instalar nada — probá el visor de Shapefiles gratuito directo en tu navegador.

¿Encontraste un error, o una trampa que se nos pasó? Escribinos. Esta página la volvemos a probar, no la copiamos y pegamos.

Última verificación: 14 de julio de 2026.

Artículos Relacionados

Navegação