DOCS · UPGRADING · V2 → V3 MIGRATION

Migrating from v2 to v3

v3 is a ground-up rewrite on cpp.js: instead of a hand-maintained wrapper around five GDAL programs, the GDAL C++ classes are bound automatically and your bundler wires the assets. This page maps the main v2 calls to their v3 equivalents.

STATUS v3 is available (npm install gdal3.js). The v2 line (2.8.x) stays on npm and keeps receiving fixes; the JPEG/ZSTD/LERC codec PRs landed on the v2 branch in April and May 2026. Migrate when it suits you.

What changed, in one paragraph

In v2 you imported one package, called initGdalJs({ path, … }) with hand-configured asset paths, and used program-shaped helpers like Gdal.ogr2ogr(dataset, args). In v3 you import GDAL's C++ headers as JavaScript modules (import { initCppJs, Gdal } from 'gdal3.js/Gdal.h'), and a cpp.js bundler plugin (Vite, Webpack, Rollup, Rspack or Metro) wires the wasm, data and worker assets automatically. Programs became methods on the Dataset class, and the same imports run as a real native library on iOS and Android.

Installation

v2 → v3 · install & wire the bundler
# v2
npm install gdal3.js@2

# v3
npm install gdal3.js
npm install -D @cpp.js/plugin-vite   # or -webpack / -rollup / -metro
vite.config.ts · the whole bundler setup
import { defineConfig } from 'vite';
import cppjs from '@cpp.js/plugin-vite';

export default defineConfig({
  plugins: [cppjs()],
});

That replaces all of v2's CopyWebpackPlugin blocks, ?url imports and paths configuration, the source of most v2 setup issues. Framework-specific notes live in the frameworks guide.

API mapping (old → new)

v2v3
import initGdalJs from 'gdal3.js'import { initCppJs, Gdal } from 'gdal3.js/Gdal.h' (+ side-effect imports for Dataset.h, Driver.h, GCP.h, SubdatasetInfo.h)
import … from 'gdal3.js/node.js'Same import everywhere: the plugin picks the right build per platform
initGdalJs({ path, paths })initCppJs(): asset paths resolved by the bundler plugin
initGdalJs({ useWorker })initCppJs({ useWorker: true })
Gdal.open(file) (a File object)Gdal.openEx(path): put bytes in OPFS or /vsimem/ first; see VFS guide
Gdal.open(f, opts, ['vsizip'])Gdal.openEx(path, flags, allowedDrivers, openOptions, siblingFiles), or open a /vsizip/… path directly
Gdal.ogr2ogr(ds, args)ds.vectorTranslate(outPath, opts)
Gdal.gdal_translate(ds, args)ds.translate(outPath, opts)
Gdal.gdalwarp(ds, args)Gdal.warp(destPath, dstDS, await Module.toVector('VectorDataset', [srcDS]), opts)
Gdal.gdal_rasterize(ds, args)ds.rasterize(outPath, opts)
Gdal.gdalinfo(ds) / ds.infods.info(opts) · ds.vectorInfo(opts) · ds.multiDimInfo(opts)
args: ['-f', 'GeoJSON']const opts = await Module.toVector('VectorString', ['-f', 'GeoJSON'])
output name via outputNameYou pass the full output path as the first argument
Gdal.getFileBytes(path)Outputs are real files in OPFS / host FS. Read them with the platform FS (browser: navigator.storage); list with Module.getFileList(dir)
getOutputFiles() / .all listds.getFileList() (per dataset) or Module.getFileList(dir)
Gdal.close(ds)ds.close()
Gdal.drivers.raster / .vectorawait Module.toArray(await Gdal.getDrivers()), each with isRaster() / isVector() / isWritable()
config: { env: { KEY: 'V' } }Gdal.setConfigOption('KEY', 'V')
logHandler / errorHandlerUnchanged: still initCppJs options. The error stack adds Gdal.getLastErrorMsg() / errorReset(); see error handling

Breaking changes

Common pitfalls

Forgetting Module.toVector for options

Program methods take a C++ vector<string>, not a JS array. Convert once: const opts = await Module.toVector('VectorString', ['-f', 'GPKG']).

Writing into a directory that doesn't exist

GDAL won't create intermediate directories: that's the classic v2 error ERROR 4: Failed to create … No such file or directory (issue #69). Create the tree first: await Module.FS.mkdirTree('/opfs/myapp/output').

Expecting output on the real disk in the browser

There is no real disk in a tab. Outputs land in the virtual filesystem, OPFS-backed when you run in a worker (useWorker: true), where it is on by default; pass fs: { opfs: false } to opt out. The VFS guide covers reading results back and offering downloads.

Multi-file formats (Shapefile)

A Shapefile conversion produces .shp + .shx + .dbf (+ .prj). Collect them with ds.getFileList() instead of assuming one path, same story as v2's .all attribute (issue #45).

Unknown-option errors come from GDAL, not the wrapper

Both v2 and v3 hand your option array straight to GDAL's own option parsers (GDALTranslateOptions & friends), so the native CLI documentation applies as-is and an "unknown option" error is GDAL's own. The practical difference is the GDAL version: v3 ships 3.13.1 (v2 is on 3.8), so some switches the older build rejected now parse.

Will v2 still be maintained?

Uncertain, honestly. 2.8.x is still on npm and got fixes as recently as April to May 2026 (the GeoTIFF codecs and a worker memory-leak fix), but continued maintenance isn't guaranteed: new work goes into v3, and v2 patches depend on spare time and community PRs. There's no removal date, but no firm commitment either, so plan to migrate to v3 when you can.