DOCS · GUIDE

Architecture & internals

One C++ recipe, three runtimes. v3 binds GDAL's C++ API automatically and compiles the same sources to WebAssembly for the web and to real native libraries for mobile.

The binding pipeline

gdal3.js declares a thin C++ surface: Gdal, Dataset, Driver, GCP, SubdatasetInfo headers that wrap GDAL's C API in classes. cpp.js turns those headers into JavaScript modules: on the web through an embind binding compiled with Emscripten, on mobile through a JSI bridge. There is no hand-written glue per function. Adding a GDAL utility to the API is mostly adding its declaration to a header.

Your bundler resolves import { Gdal } from 'gdal3.js/Gdal.h' via the cpp.js plugin, which generates the JS bridge, ships the right binary for the target, and wires asset URLs. The C++ never appears in your bundle; the wasm and data files load lazily at initCppJs().

Web vs mobile runtimes

ASPECTBROWSER / NODEIOS / ANDROID
BinaryWebAssembly (st & mt variants)Native library (arm64 + x86_64)
BridgeembindJSI (New Architecture supported)
FilesystemVirtual FS: OPFS / in-memory (guide)Real device filesystem
Memory ceilingTab limits apply (see memory)App-level limits: no wasm sandbox cap
ThreadinguseWorker + mt build (guide)Native threads

Package map

PACKAGEROLE
gdal3.jsThe recipe: C++ headers + sources that define the JS-facing classes
@gdal3.js/wasmPrebuilt WebAssembly artifacts consumed by the bundler plugins
@gdal3.js/wasm-bundleSelf-contained UMD builds (browser / Node / edge; st & mt) for use without a bundler
@gdal3.js/wasm-bundle-minimalSlimmer driver subset (in the works)
@gdal3.js/ios · @gdal3.js/androidPrebuilt native libraries for React Native

GDAL itself, with its dependency stack (PROJ, GEOS, SQLite, SpatiaLite, libtiff with JPEG/ZSTD/LERC, and more), comes prebuilt from the cpp.js package registry, currently GDAL 3.13.1.

Why the cpp.js rewrite

v2 was a single hand-maintained Emscripten build: every exposed function needed wrapper code, every bundler needed bespoke asset instructions, and mobile was out of reach. Three pressures drove the rewrite: the issue tracker was dominated by bundler/path setup problems; each new GDAL utility cost real wrapper work (gdalbuildvrt and friends waited years); and iOS browser memory limits (issue #96) capped what web delivery could do. cpp.js answers all three: plugins own the asset story, headers are bound automatically, and the same recipe compiles natively for phones.

Maintainability

The driver registry is asserted in CI on every build (Playwright suites boot the wasm and exercise read/write across the registry). Upstream GDAL versions arrive by bumping one dependency. And because bindings are generated, surface area grows by editing headers, which is how v3 picked up buildVRT, demProcessing, grid, nearblack, footprint and the multidim tools in one sweep.