[PROJ] proj.js: JavaScript bindings for PROJ - both Node.js native & browser WASM

Momtchil Momtchev momtchil at momtchev.com
Sun Jan 4 08:21:03 PST 2026


I am excited to announce the public availability of what should be a 
usable beta version of proj.js - JavaScript bindings for PROJ.


https://github.com/mmomtchev/proj.js

https://www.npmjs.com/package/proj.js


proj.js is a dual-environment npm package that works both in the browser 
(compiled to WASM) and in Node.js (compiled as a native module for 
Linux, Windows and macOS).

It exports both the new C++ API and the older C API to JavaScript in two 
separate modules.

The package is bundler-friendly and leverages Node.js 16 exports to 
automatically load either the native version or the WASM version. It 
comes with prebuilt binaries for WASM, Linux x86, Windows x86, macOS x86 
and macOS arm8.

Currently the only documentation are the unit tests and the TypeScript 
definitions. All methods are covered by TypeScript definitions which can 
be used as online help in IDEs that parse them. With very few 
exceptions, all JS methods match the C and C++ API 1:1.

This is a new generation of C/C++ to JS project that leverages three new 
important technologies in the JavaScript world:
* SWIG JSE which renders possible the automatic generation of high 
quality native-feel wrappers with minimal code (2000 lines of SWIG code 
for 200k lines of C/C++ code, an impressive 1:100 reduction)
* emnapi which renders all Node-API modules compatible with WASM using 
the same API
* hadron which renders possible the cross-platform compilation of 
complex C/C++ projects for JavaScript

The whole project is entirely synchronous JavaScript on purpose - most 
of the methods are fast enough to be used on the main loop and adding 
async support - which is a simple flip-switch in SWIG - would add a very 
restrictive requirement to the WASM module - 
https://web.dev/articles/coop-coep - that is best avoided unless there 
is a good reason for it.

The current version is available on npm and should be more or less 
usable. The unit testing is somewhat incomplete, but the nominal 
codepath of all SWIG typemaps have been tested at least once on each 
platform, including an ASAN build.

Currently the main issue is the size of the WASM bundle which renders it 
impractical for most websites. Currently, the absolute minimum is about 
1.2MB w/o libtiff, w/o proj.db, after compression and using only the C 
API. There are various options for optimising this size, but bear in 
mind, that proj.js will always be significantly larger than proj4js.

This project, together with magickwand.js (ImageMagick for JS) - which 
is my basic tutorial, will be part of the SWIG JSE tutorials. proj.js is 
about advanced SWIG JSE techniques - the C++ API contains many modern 
C++>=11 features and expressing the C API in a garbage-collected 
language is not very straightforward. magickwand.js has a 1:400 code 
reduction ratio.

You should know that I am not a very advanced PROJ user and my main 
interest is SWIG (though I am a user), but:

* All stability problems, including memory leaks, will be thoroughly 
investigated, in the limits of what my current access to hardware allows
* If there are methods that are incorrectly wrapped, I will fix them
* I will fix bundler problems, this is something that is expected to 
work well, I currently have examples/testing set for the major bundlers 
such as webpack, vite, rollup and the now obsolete create-react-app
* I do not plan to re-implement any of PROJ’ missing features in WASM - 
mainly the file and the network API - but if someone else does (I saw 
there are people working on it), I will integrate it
* I do not plan to work on reducing PROJ’ own size, but I may eventually 
add emscripten split module support in order to reduce the initial bundle

The current beta:

* WASM must be built with emscripten 4.0.8

    https://github.com/mmomtchev/hadron/issues/79

    Will be fixed in the next hadron release.

* Leaks memory if loaded/unloaded repeatedly in a Node.js worker_thread

    https://github.com/nodejs/node/issues/45088

    As the root cause is in Node-API itself, this won't be fixed in the 
near future, I am looking at alternative solutions. Currently every time 
you create a worker_thread that uses proj.js, when it quits, part of the 
memory is not freed until the main thread exits.



-- 
Momtchil Momtchev <momtchil at momtchev.com>



More information about the PROJ mailing list