Skip to main content
This guide shows you how to create a new .gpkg file, define tables, and populate them with features and tiles.
1

Create a new GeoPackage

GeoPackageManager.create() creates the file on disk in Node.js, or creates an in-memory database in the browser.
import {
  GeoPackageManager,
  setCanvasKitWasmLocateFile,
} from '@ngageoint/geopackage';

setCanvasKitWasmLocateFile(
  file => `/path/to/node_modules/@ngageoint/geopackage/dist/canvaskit/${file}`
);

const geoPackage = await GeoPackageManager.create('/path/to/output.gpkg');
The path argument is ignored in browser environments. The library automatically creates the minimum required GeoPackage metadata tables on creation.
2

Create a feature table

Use createFeatureTableWithMetadata() to create the user table and all required GeoPackage metadata (geometry columns, contents, SRS) in one call.
import {
  FeatureTableMetadata,
  GeometryColumns,
  BoundingBox,
  FeatureColumn,
  GeoPackageDataType,
} from '@ngageoint/geopackage';
import { GeometryType } from '@ngageoint/simple-features-js';

// 1. Define the geometry column
const geometryColumns = new GeometryColumns();
geometryColumns.setTableName('cities');
geometryColumns.setColumnName('geometry');
geometryColumns.setGeometryType(GeometryType.POINT);
geometryColumns.setSrsId(4326);
geometryColumns.setZ(0);
geometryColumns.setM(0);

// 2. Define additional attribute columns
const columns = [
  FeatureColumn.createColumn('name', GeoPackageDataType.TEXT),
  FeatureColumn.createColumn('population', GeoPackageDataType.INTEGER),
];

// 3. Build the metadata and create the table
const metadata = FeatureTableMetadata.create(
  geometryColumns,
  columns,
  undefined,
  BoundingBox.worldWGS84(),
);

const featureTable = geoPackage.createFeatureTableWithMetadata(metadata);
Use the shorthand createFeatureTableWithProperties() when you only need to specify column names and data type strings:
geoPackage.createFeatureTableWithProperties('cities', [
  { name: 'name', dataType: 'TEXT' },
  { name: 'population', dataType: 'INTEGER' },
]);
3

Insert feature rows

Get a FeatureDao for your table, create a new row, set the geometry and attribute values, then save it.
import { GeoPackageGeometryData } from '@ngageoint/geopackage';
import { Point } from '@ngageoint/simple-features-js';

const featureDao = geoPackage.getFeatureDao('cities');
const newRow = featureDao.newRow();

// Set the geometry (WGS84 longitude, latitude)
const point = new Point(-77.0369, 38.9072);
const geometryData = GeoPackageGeometryData.create(4326, point);
newRow.setGeometry(geometryData);

// Set attribute values
newRow.setValue('name', 'Washington D.C.');
newRow.setValue('population', 689545);

// Write the row and get its row ID
const rowId = featureDao.create(newRow);
console.log('Created feature row:', rowId);
4

Create a tile table

Use createTileTableWithMetadata() to create a tile table along with its tile matrix set and contents entries.
import { TileTableMetadata, BoundingBox } from '@ngageoint/geopackage';

const tileTable = geoPackage.createTileTableWithMetadata(
  TileTableMetadata.create(
    'world_tiles',            // table name
    BoundingBox.worldWGS84(), // content bounding box
    4326,                     // content SRS ID
    BoundingBox.worldWGS84(), // tile bounding box
    4326,                     // tile SRS ID
  )
);
After creating the tile table, you also need to define TileMatrix rows for each zoom level before inserting tiles. These describe how many columns and rows exist at each zoom level.
5

Insert tiles

addTile() is the simplest way to insert a tile — pass the raw image bytes, table name, zoom level, tile row, and tile column.
import fs from 'fs';

const tileBytes = fs.readFileSync('/path/to/tile.png');

geoPackage.addTile(
  tileBytes,       // Uint8Array or Buffer
  'world_tiles',   // table name
  0,               // zoom level
  0,               // tile row
  0,               // tile column
);
To insert many tiles programmatically, iterate over your tile source and call addTile() for each one:
for (const { bytes, zoom, row, col } of myTileSource) {
  geoPackage.addTile(bytes, 'world_tiles', zoom, row, col);
}
6

Close and save

In Node.js, the file is written incrementally as you make changes. Call close() when finished to flush any remaining writes and release the database connection.
geoPackage.close();
In browser environments, use export() to retrieve the database as a Uint8Array before closing if you want to save it:
const bytes = await geoPackage.export();
// bytes is a Uint8Array you can download or send to a server
geoPackage.close();

Build docs developers (and LLMs) love