node-gtk is a gobject-introspection library
for nodejs. It makes it possible to use any introspected C library, such as GTK,
usable. It is similar in essence to GJS
or PyGObject. Please note this project is
currently in a alpha state.
Supported Node.js versions: 20, 22, 24 (other versions may work but are untested)
Supported platforms:
- Linux — prebuilt binaries available
- macOS — prebuilt binaries available
- Windows — prebuilt binaries available (but read Windows)
Below is a minimal example of how to use node-gtk:
const gi = require('node-gtk');
const GLib = gi.require('GLib', '2.0');
const Gtk = gi.require('Gtk', '4.0');
const Adw = gi.require('Adw', '1');
const loop = GLib.MainLoop.new(null, false);
const app = new Adw.Application('com.github.romgrk.node-gtk.hello', 0);
app.on('activate', () => {
const content = new Gtk.Box({ orientation: Gtk.Orientation.VERTICAL });
content.append(new Adw.HeaderBar());
content.append(new Gtk.Label({ label: 'Hello Adwaita!', vexpand: true }));
const window = new Adw.ApplicationWindow(app);
window.setTitle('node-gtk');
window.setDefaultSize(300, 120);
window.setContent(content);
window.on('close-request', () => (loop.quit(), app.quit(), false));
window.present();
gi.startLoop();
loop.run();
});
process.exit(app.run([]));You can also easily create custom applications:
A web browser (using WebKit2GTK)
The Usage example above is CommonJS. node-gtk also works under ESM, but the
blocking main-loop calls (GLib.MainLoop.run, Gio/Gtk.Application.run,
Gtk.main) return immediately instead of blocking and don't return a
value — so make the run call the last statement and exit from your handler:
app.on('activate', () => {
// ...build the window...
window.on('close-request', () => (loop.quit(), app.quit(), false));
window.present();
gi.startLoop();
loop.run(); // returns immediately under ESM; do cleanup/exit in the handler
});
app.run([]); // not `process.exit(app.run([]))` — the return value is unavailableCommonJS (and signal callbacks) are unaffected. For the why and the design trade-off, see #449.
node-gtk can generate TypeScript declarations for the libraries you use, straight from the GObject-Introspection typelibs installed on your machine — so the types always match your actual library versions and node-gtk's own runtime shape (camelCase methods, signal callbacks, nullability, etc.).
# generates ./node_modules/.node-gtk-types (a hidden, git-ignored cache)
npx node-gtk generate-types Gtk-4.0 Adw-1The command emits one declaration file per namespace (plus the full dependency
closure) and a node-gtk.d.ts shim. Point your tsconfig.json at it:
Then gi.require is fully typed — the namespace is inferred from the string
arguments:
import * as gi from 'node-gtk'
const Gtk = gi.require('Gtk', '4.0') // typed as the Gtk-4.0 namespace
const win = new Gtk.ApplicationWindow({ title: 'Hello', defaultWidth: 400 })
win.on('close-request', () => false) // signal name + callback are typedYou get typed constructor properties (including inherited and interface ones),
camelCase methods with real return types, GI nullability, typed signal
overloads, enums, bigint for 64-bit integers, out-parameters surfaced as the
return value, and cross-namespace types. GNOME's API documentation is included
as JSDoc (with @param/@returns), so editors show it on hover — this reads the
.gir files installed by the libraries' -dev/-devel packages; pass
--no-docs for leaner output if they aren't installed or you don't want them.
Because the output is a generated cache under node_modules, add a postinstall
script so it regenerates on install:
{ "scripts": { "postinstall": "node-gtk generate-types Gtk-4.0 Adw-1" } }Run npx node-gtk generate-types --help for options.
- Install
node-gtkitself - Install the native libraries you use (see examples per platform below)
npm install node-gtk
# This installs a prebuilt binary when one is available for your platform and
# Node.js version, otherwise it falls back to building from source.# archlinux
pacman -S gtk4
# ubuntu
apt install libgtk-4-1brew install gtk4Windows doesn't have the dependencies we need in a package manager, therefore
node-gtk ships prebuilt versions of GTK 4 / Adwaita runtime (DLLs, typelibs,
icons), so npm install node-gtk is all you need if your dependency is in
our list of prebuilt libraries.
Building from source, or contributing? See Building from source.
If you'd like to help, we'd be more than happy to have support. To setup your development environment, you can
run npm run configure. You can then build the project with npm run build. To generate the compile_commands.json
for LSP to work nicely, you can use bear as bear -- npm run build.



{ "compilerOptions": { "moduleResolution": "node16", "paths": { "node-gtk": ["./node_modules/.node-gtk-types/node-gtk.d.ts"] } } }