GDAL in the browser.
And now on mobile.

GDAL and a deep C++ stack (PROJ, GEOS, libtiff and more), compiled to WebAssembly for the web and to native modules for iOS and Android. Read, write, and transform raster and vector formats entirely on-device. No server. No upload.

Read the docs
What's new in v3 v2 → v3 guide
API
Full GDAL, zero glue
React Native
iOS · Android
Threading
Workers + multi-threaded
GeoTIFF / COG
+ JPEG · ZSTD · LERC
Dependencies
add · drop · tune
Optimization
dead-code elimination
License
MIT
Engine
cpp.js
i.Why gdal3.js

Full GDAL, everywhere JavaScript runs.

One library, the same API across every runtime. Process raster and vector geodata where the user already is, without standing up a backend or shipping native binaries to every device.

01
Runs on the client, not your servers.
Every read, write and reprojection runs on the user's own device. There's no backend to build, scale or pay for, and sensitive data never leaves the device, so the work scales across your users instead of your servers.
NO BACKEND ON-DEVICE · PRIVATE
02
The full GDAL API.
Not a hand-picked subset: every GDAL and OGR class and method is exposed, the same surface you would use in C++, now in JavaScript. Built on GDAL 3.13.1, with 189 format drivers compiled in.
FROM v3.0 · GDAL 3.13.1
03
One codebase, every platform.
The same code runs everywhere JavaScript does: WebAssembly in the browser and Node, and real native GDAL over JSI on iOS and Android (New Architecture, Expo supported). One API surface, no per-platform rewrites.
Browser Node React Native iOS Android Cloudflare Workers
04
GDAL and a deep stack.
GDAL leans on a deep stack of C++ libraries, and gdal3.js compiles a broad set of them in, the real upstream code at pinned versions, not JavaScript reimplementations. Versions and licenses →
GDAL PROJ GEOS SpatiaLite SQLite libtiff libgeotiff libjpeg-turbo libwebp Zstd LERC libiconv Expat zlib curl OpenSSL
05
Add or drop any dependency.
Tune which libraries compile into the build and how they're built. Drop GEOS, SpatiaLite and libiconv for a smaller, fully permissive output, or add a library GDAL doesn't bundle by default.
Add dependencies Remove dependencies Compile flags Permissive build
FULLY CONFIGURABLE BUILD
06
Bundlers just work.
Add the official plugin and the wasm, data and worker assets wire themselves, no asset-path hacks, no copy-plugin gymnastics. All the setup pain that filled the v2 issue tracker is gone.
PLUGINS VITE · WEBPACK · ROLLUP · RSPACK · METRO
07
OPFS & big files.
Work on multi-gigabyte rasters through the Origin Private File System: files persist across reloads and never need to fit in a single upload, because there is no upload.
STORAGE OPFS-BACKED VIRTUAL FS
08
Multi-threaded, full speed.
With pthreads, GDAL spreads heavy reads, writes and warps across every core, close to native throughput. And it works off the main thread in a Web Worker, so the UI never blocks.
VIA MULTI-THREADED WASM · WEB WORKERS
09
Heavy math, SIMD-accelerated.
Reprojection, resampling and warps are millions of tiny calculations. SIMD does many at once instead of one at a time, so heavy operations finish faster, on every platform: WebAssembly SIMD on web and Node, native SIMD on iOS and Android.
VIA WASM + NATIVE SIMD
10
All you need is Docker.
Compiling GDAL and its dependencies normally means wrangling Emscripten and native SDKs. Here the whole toolchain is standardized in a Docker image: the only thing you install is Docker, and every build comes out identical, anywhere.
BUILD ANYWHERE JUST DOCKER
11
Ship only what you use.
Unused functions and code paths are stripped at compile time through dead-code elimination and link-time optimization, so the wasm you download stays as lean as the API surface your app actually touches.
SMALLER BUILDS DEAD-CODE ELIMINATION · LTO
12
GDAL & PROJ data, auto-wired.
GDAL and PROJ need data files at runtime, PROJ's coordinate database and GDAL's format support tables. The plugin copies them into your app and sets the environment so they're found, so coordinate transforms and drivers resolve with no data paths to wire by hand.
AUTO-WIRED GDAL_DATA · PROJ_LIB
ii.Performance

Roughly native speed, no server.

What do you give up by running GDAL in the browser? Not much. Common operations land within about 2x of native GDAL, several on par. And the work runs on the user's device, so you skip the upload and download a backend would need, usually a bigger cost than the wasm overhead itself.

01
58 98 ms
Reproject a 4 MP GeoTIFF, native versus the browser: the largest gap here, about 1.7x at one thread. With two threads the browser nearly halves it, near 50 ms.
WARP NATIVE → BROWSER
02
31 28 ms
Write a Cloud-Optimized GeoTIFF: on par with native, right in the browser.
COG ON PAR
03
217 173 ms
Convert 50k features to FlatGeobuf: vector conversion runs at full speed in the browser, here even ahead of the native CLI.
OGR2OGR VECTOR
iii.Quick start

Pick a runtime. Convert a file.

A minimal reprojection pipeline. The same input, the same output, on every supported runtime. Just a different way to read the file in.

main.ts · vite + @cpp.js/plugin-vite
// vite.config.ts, one line:  plugins: [cppjs()]
import 'gdal3.js/Dataset.h';
import { initCppJs, Gdal } from 'gdal3.js/Gdal.h';

const Module = await initCppJs({ useWorker: true, fs: { opfs: true } });

// put the user's file into OPFS; gdal sees it as /opfs/…
const dir = await navigator.storage.getDirectory();
const fh  = await dir.getFileHandle(file.name, { create: true });
const ws  = await fh.createWritable(); await ws.write(file); await ws.close();

const ds   = await Gdal.open(`/opfs/${file.name}`);
const opts = await Module.toVector('VectorString',
  ['-f', 'GPKG', '-t_srs', 'EPSG:3857']);
const out  = await ds.vectorTranslate('/opfs/out.gpkg', opts);
await out.close();  // out.gpkg persists in OPFS, survives reloads
v3 wasm: ≈14 MB gzipped on first load (189 drivers + PROJ data) · lazy-loaded · cached after first run Full getting-started guide →
iv.Supported formats

If GDAL reads it, so do you.

All 189 drivers from GDAL's registry are bundled with every release: no à-la-carte builds. The list below is a sample; search the registry for what you need.

.tifGeoTIFF GTiffRW
.geojsonGeoJSON GeoJSONRW
.shpESRI Shapefile ESRI ShapefileRW
.gpkgGeoPackage GPKGRW
.fgbFlatGeobuf FlatGeobufRW
.kmlKeyhole Markup KMLRW
.gpxGPS Exchange GPXRW
.csvComma-Separated CSVRW
.cogCloud-Optimized GeoTIFF COGRW
.pngPortable Network Graphics PNGRW
.jp2JPEG 2000 JP2OpenJPEGRW
.mbtilesMBTiles MBTilesRW
.ncNetCDF netCDFRO
.hdf5Hierarchical Data Format HDF5RO
.lasASPRS LiDAR LASRO
.gmlGeography Markup GMLRW
Showing a 16-driver sample · 189 drivers ship in the build Browse the drivers →
v.Trusted

Used in production.

gdal3.js has powered geospatial work in browsers and on servers for years. v3 is the next chapter for the same widely used engine.

vi.Shaped by its issue tracker

You asked. It shipped.

Most of what's new started as somebody's GitHub issue, with merged contributions from GDAL's own lead maintainer among them. A sample of requests that became features.

01
"Missing codec JPEG / ZSTD."
JPEG-, ZSTD- and LERC-compressed GeoTIFFs & COGs used to fail on open. Community PRs wired libjpeg-turbo, zstd and LERC into the build, for reading and writing.
VIA #103 · #99 → PRs #105 / #107 / #108
02
"Where did my output go?"
The virtual filesystem confused everyone. It is now a first-class API (readDir, unlink, rename, copyFile, mkdir), plus clearFS() to reset between conversions.
VIA #56 · #44 · #90 → PR #109 + v3 FS API
03
"What about the other tools?"
v3's zero-glue binding makes whole tool families cheap to expose: gdalbuildvrt, gdaldem, gdal_grid, nearblack, footprint, multidim and GCP georeferencing are in; gdal_polygonize (#93) is next.
VIA #58 · #95 → v3 API · 13 OPERATIONS
04
Open options, config, logs.
-oo open options, GDAL config options, log/error handlers and /vsizip/-style open prefixes all arrived as community PRs against v2, and carry into v3.
VIA #41#42 · #40 · #63 · #71#62
05
"iOS Safari kills the tab."
Mobile-browser memory limits capped real workloads. v3's answer is structural: run GDAL as a native module on iOS and Android instead of wasm in a browser tab.
VIA #96 → REACT NATIVE SUPPORT
06
Fixed before you hit it.
A worker-promise leak that crashed long tile pipelines, planetary PDS formats for NASA workflows, Electron absolute paths: community-reported, merged, released.
VIA #104 · #70 + #66 · #89
vii.Looking for the converter?

The converter has a new home.

The GIS converter app, built on this library, moved to its own domain and was rebuilt with a new design as it grows into a full toolkit. The engine and the privacy are unchanged: your files still never leave the browser.

CONVERTER · MOVED & REDESIGNED

Convert geodata. In your browser.

Drop your files in, get the format you need out. Reproject, warp, repackage, all on-device, your files never leave the browser. Now at its own address with a redesigned interface, free to grow into a full toolkit.

Open geosmith.dev Same engine, new look. Free, no signup, no upload.
WAS gdal3.js.org geosmith.dev
x.FAQ

Questions, quickly answered.

The things people ask first. If yours isn't here, open an issue on GitHub. We read them all.

1 How do I migrate from v2 to v3? +

v3 is a ground-up rewrite on cpp.js, and the API changed with it. The headlines:

• You import GDAL's headers as modules (import { initCppJs, Gdal } from 'gdal3.js/Gdal.h'), and a bundler plugin (Vite, Webpack, Rollup, Rspack or Metro) wires the wasm, data and worker assets automatically. No more copy-plugin and paths configuration.
• The v2 helpers (Gdal.ogr2ogr(dataset, args)) became dataset methods: ds.vectorTranslate(outPath, opts), plus class-level access to Dataset, Driver and GCP.
• v2 (2.8.x) stays on npm and keeps working; migrate when you're ready.

The full diff lives in the v2 → v3 migration guide.

2 Can I open remote files: /vsicurl/, S3, WMS? +

Not yet over the network. /vsicurl/ needs a curl that speaks browser-fetch, and that work is tracked in issue #67. What works today: fetch the file yourself and hand the bytes to gdal3.js, plus local VSI layers like /vsizip/ (zipped Shapefiles open directly) and in-memory /vsimem/.

3 What's the bundle cost? +

The v3 full build is roughly 14 MB gzipped on first load: ~11.5 MB of wasm plus ~2.2 MB of driver/PROJ data. That's the price of the complete driver registry with the new codecs; it loads lazily when you call initCppJs() and is cached after the first run.

If that's too much, slimmer driver subsets are the plan for the minimal bundle, and on React Native the question disappears. GDAL ships inside the app binary, not over the network.

4 How does it compare to native GDAL? +

Functionally: it's the same GDAL, with the same option flags. If your script works with ogr2ogr on the command line, the same flags work here.

Performance-wise, in the browser expect roughly 1.5× to 3× the wall-clock time of native, depending on the operation. On iOS and Android there is no wasm penalty at all; v3 runs GDAL as a real native library. In Node, if you need maximum throughput and can install native binaries, a native binding will still be faster; gdal3.js trades that for zero native dependencies.

5 Does it work offline? +

Yes. After the wasm and data files are cached (first run), the library runs entirely offline, including in a service-worker-cached PWA or a React Native app that has no network. There are no runtime calls to a GDAL server.

6 What does the license mean for my app? +

gdal3.js is released under the MIT License, but the default build bundles a few LGPL libraries (GEOS, SpatiaLite, libiconv), so the package you ship is LGPL-2.1-or-later by default. For a build with permissive licenses only, override the cpp.js config to exclude those three (with reduced geometry/encoding support). Whether a given build fits your project is for you to confirm against the license terms; the license page has the full breakdown.

This was settled early in the project's history (issue #36, GPL → LGPL by community request).

7 Will v2 still be maintained? +

Uncertain. The 2.8.x line is still on npm and got fixes as recently as April to May 2026 (the JPEG/ZSTD/LERC codecs and a worker memory-leak fix), but continued maintenance isn't guaranteed: new features land in v3 only, and v2 patches depend on time and community PRs. No fixed end-of-life date, but no promise either, so plan to migrate with the migration guide.

8 Which GDAL version does v3 ship? +

GDAL 3.13.1, with PROJ and the rest of the native stack, prebuilt through the cpp.js package registry. Upstream releases are tracked as dependency bumps, so version updates are routine rather than rebuild projects. The v2 line is on GDAL 3.8.x.