DOCS · GETTING STARTED · QUICK START

Quick start

Setup is two steps: get a cpp.js project (scaffold a fresh one, or add cpp.js to an app you already have), then drop in gdal3.js. After that you import GDAL like a module and convert your first file on any runtime: browser, Node or React Native.

Prerequisites

gdal3.js builds GDAL to WebAssembly (and to native libraries) through cpp.js, so cpp.js's build toolchain needs to be in place first:

Install links and the full list are in the cpp.js prerequisites.

Set up with an AI assistant

Using Cursor, Claude Code, Copilot or similar? Hand it this prompt and it'll wire gdal3.js into your project:

prompt
Set up gdal3.js v3 in my project. Detect my bundler and package manager, then: install gdal3.js, the matching @cpp.js/plugin-* (vite / webpack / rspack / rollup / metro), and the platform package (@gdal3.js/wasm for web); create cppjs.config.js at the project root importing "@gdal3.js/wasm/cppjs.config.mjs"; add the cpp.js plugin to my bundler config; then add a minimal example that opens a file with Gdal.open. Reference: https://gdal3.js.org/docs/getting-started/

Prefer to wire it up yourself? Keep going.

New project

The fastest way to a cpp.js-ready project is to scaffold one. The bundler, its cpp.js plugin and a starter cppjs.config.js come wired, with nothing to configure by hand.

shell
npm init cpp.js@beta

Answer the prompts to pick whatever target fits, web (React, Vue, Svelte or vanilla), mobile (React Native), Node or Cloudflare Workers, plus a framework and bundler where they apply. That's your cpp.js project, now add gdal3.js.

Add to an existing project

Already have an app? Integrate cpp.js into it: add the bundler plugin and wire it in. Below it's Vite; Webpack, Rollup, Rspack and Metro (React Native) follow the same shape with their own plugin, see the bundlers guide.

shell
npm install -D @cpp.js/plugin-vite
vite.config.ts
import { defineConfig } from "vite";
import viteCppjsPlugin from "@cpp.js/plugin-vite";

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

That's cpp.js wired in. It reads a cppjs.config.js from your project root, which you'll create in the next step. Now add gdal3.js.

Add gdal3.js

However you got here, you now have a cpp.js project. Add GDAL, the package depends on your target:

shell · web, Node, Cloudflare
npm install gdal3.js @gdal3.js/wasm
shell · React Native
npm install gdal3.js @gdal3.js/android @gdal3.js/ios

Then declare it in cppjs.config.js at your project root. Scaffolded a project? The file is already there with a sample dependency, swap it out. Added cpp.js to an existing app? Create it now. Pick the config for your target:

cppjs.config.js · web, Node, Cloudflare
import wasm from "@gdal3.js/wasm/cppjs.config.mjs";

export default {
  dependencies: [wasm],
  paths: { config: import.meta.url },
};
cppjs.config.js · React Native
import ios from "@gdal3.js/ios/cppjs.config.mjs";
import android from "@gdal3.js/android/cppjs.config.mjs";

export default {
  dependencies: [ios, android],
  paths: { config: import.meta.url },
};

gdal3.js is the API; @gdal3.js/wasm carries the prebuilt GDAL binaries for web, Node and Cloudflare, while @gdal3.js/android and @gdal3.js/ios ship the native libraries. Now write code, pick your runtime below.

Use it

Write your pipeline in C++ and call it from JS, or drive GDAL straight from JavaScript, the API is the same shape either way. The C++ path reaches the complete GDAL API and runs a whole pipeline in one call without crossing the JS↔wasm boundary each time; the JavaScript path is the quickest to wire up. More on the tradeoff in two ways to use it.

From C++

Put your C++ under src/native: declare a class, implement it, and cpp.js exposes it to JavaScript. You reach GDAL however you like, version() reads GDAL_RELEASE_NAME straight from GDAL's own <gdal_version.h>, while convert() uses the high-level wrapper to run a full pipeline (to GeoPackage, reprojected to Web Mercator) with options as a plain std::vector<std::string>.

src/native/native.h
#pragma once
#include <string>

class Native {
public:
  static std::string version();
  static std::string convert(std::string inputPath, std::string outputPath);
};
src/native/native.cpp
#include "native.h"
#include <gdal_version.h>
#include <gdal3js/Gdal.h>
#include <gdal3js/Dataset.h>

std::string Native::version() {
  return GDAL_RELEASE_NAME;   // "3.13.1", straight from GDAL's own header
}

std::string Native::convert(std::string inputPath, std::string outputPath) {
  auto ds  = Gdal::open(inputPath);
  auto out = ds->vectorTranslate(outputPath, {"-f", "GPKG", "-t_srs", "EPSG:3857"});
  out->close();
  return outputPath;
}

Then import the header from your app code and call either method:

src/main.js
import { initCppJs, Native } from "./native/native.h";

await initCppJs();
const version = await Native.version();                      // GDAL version string
const out     = await Native.convert(inputPath, outputPath);

From JavaScript

Prefer to stay in JavaScript? Import the wrapper, plus GDAL's own headers when you want a raw call, and use them directly:

src/main.js
import "gdal3.js/Dataset.h";
import { initCppJs, Gdal } from "gdal3.js/Gdal.h";                 // wrapper
import { GDALGetDriverCount } from "@cpp.js/package-gdal/gdal.h";  // GDAL's own header

const Module = await initCppJs();

await GDALGetDriverCount();                                // e.g. 189, straight from GDAL

const ds   = await Gdal.openEx(inputPath);
const opts = await Module.toVector("VectorString", ["-f", "GPKG", "-t_srs", "EPSG:3857"]);
const out  = await ds.vectorTranslate(outputPath, opts);
await out.close();

Where your input and output files live, and the optional init settings, are covered in the virtual file system and configuration guides.

Where to next