Notesnook Blog

LoginSign up

NeutralinoJS: The Next Best Alternative to Electron & Tauri

By AbdullahJanuary 22, 2022
Photo by Alexandre Debiève on Unsplash

A few years back, the only way for web developers to enter into the Desktop app space was either Electron or NW.js. Both choices were not really choices at all --- both were huge, full of bloat, memory hogging frameworks but the solution was tempting to many. Huge companies like Microsoft, Slack, Discord invested into it but there were still many people who did not want to install 9 different versions of Chromium to run 9 different apps.

NeutralinoJS was not a new idea --- instead of packaging the whole Node + Chromium with every app, why not reuse the already installed browser each OS comes with? Linux & macOS have WebKit while Microsoft Windows has IE, Edge, and now Chromium. A fabulous idea in theory but complications like native support for system tray, notifications, file system access, data storage, and security made many hesitate into actually making it a thing.

Released in 2018 by a Sri Lankan programmer, Shalitha Suranga, NeutralinoJS was one of the first frameworks to properly support 3 different desktop platforms while making it extremely easy for web developers. 3 years later, it has its own Javascript client library, support for extensions, and a very minimal footprint (< 3 MB).

The next best alternative to Electron & Tauri
The next best alternative to Electron & Tauri - NeutralinoJS

While Tauri requires you to install Rust and a boatload of other things, NeutralinoJS stands on the shoulders of giants. It doesn't require learning a new language to take advantage of native capabilities. It lacks the huge npm ecosystem but supports a wide variety of system APIs under the Neutralino namespace. Currently it supports:

Ease of Use


Installing NeutralinoJS is as simple as:

npm i -g @neutralino/neu

And a few seconds later, you should have neu command available globally.

Hello Neutralino

Creating a new NeutralinoJS app is even simpler:

neu create <project-name>

However, most of the times you are either integrating into an existing codebase or you want to use a frontend framework like React. This is where NeutralinoJS shines.

Run the above command in your app's codebase. It should create a directory with the same name. All you have to do after that is edit the neutralino.config.json file. We'll edit 2 keys: url & documentRoot to point them to our framework's build directory. For React, it is:

"documentRoot": "./build/",
"url": "/index.html",

To start the app, enter:

neu run

And your app should open in a native window.

Neutralino JS app running in native window
Neutralino JS app running in native window

All in all, relative to Tauri, NeutralinoJS is extremely easy to setup and use. Of course, it doesn't have nearly all the features Tauri has but you can easily add those via native extensions.


In terms of security, NeutralinoJS is a disappointment. It hosts the web app on a local server exposed on the localhost — all you have to do to access it is open a browser and go to http://localhost:some-random-port.

That's not even the worst thing. NeutralinoJS has a Javascript client library with many helpful functions to read files, write files, and access system info etc. This library is exposed on the client side as a global variable Neutralino. If you open the Developer Console in a Neutralino app, you can literally delete & list files using:

const files = await Neutralino.filesystem.readDirectory('.');
for (let file of files) {
  await Neutralino.filesystem.removeFile(`./${file.entry}`);

And viola! All files in your current working directory are now gone.

Listing all files in current working directory
Listing all files in current working directory

Very, very dangerous. I am aware that this is done for Developer experience but if, let's say, you wanted to load untrusted content in a NeutralinoJS app, I'd seriously reconsider. Most apps, however, only load local files for which NeutralinoJS is great. It'd still have been amazing if the client library wasn't exposed as a global variable.


Extensions in NeutralinoJS are simply programs that communicate over Websockets. Naturally, this allows the program to be written in any language or framework. This opens the possibility to write the backend in NodeJS, Rust or Go while the app is rendered in the native browser.

Since it's all Websockets, stuff like converting data structures, translating function arguments, reading results etc. are automatically handled by a lot of Websocket client libraries.

Publising & Updates

NeutralinoJS has no built-in system for receiving or installing updates nor does it have a proper bundler like electron-builder to make installers for each operating system. All this makes NeutralinoJS nonviable for any but the most trivial projects.

Running the neu build -r creates a .zip file containing binaries & resources for all 3 platforms. This works but there's no desktop integration, no icons, no way to install etc.

Migrating from Electron

Suffice it to say, there is 0 API compatibility with Electron. There's no node, no npm ecosystem, nothing like that. Your best bet to migrate an Electron app to Neutralino is either rewriting the backend code to a natively compiled language like Go or Rust or you can package the whole NodeJS along as a binary.

Final verdict

Having NeutralinoJS in the Native Javascript space provides necessary competition but it falls short of a lot of things required for a native app (even a native Javascript app) --- especially security. Combine that with this being mostly a hobby project run by a single developer with little financial (or other) support from the community, and you get something that is truly wonderful but not yet there.

Initially, I had plans to migrate Notesnook from Electron to Neutralino because the feature-set of NeutralinoJS is simply amazing. However, the security & reliability provided by Electron is simply unparalleled. If the developer works on bundling & security, NeutralinoJS can become an amazing alternative to Tauri & Electron.

AbdullahLead developer of Notesnook
PREV POSTUsing React Native Skia to Build a 60 FPS Free-hand Drawing AppNEXT POST Scoped Storage in React Native: New Android 10 API for File System Access