The full JavaScript ecosystem, native on GNOME.
Use Node.js APIs, Web APIs, and DOM interfaces in GNOME desktop applications. gjsify provides native implementations backed by GNOME libraries (GLib, Gio, Soup, Cairo, GTK) — so you can use the npm packages and patterns you already know to build native Linux apps.
- 43 Node.js modules — fs, net, http, http2 (h2c + ALPN + native dispatcher), crypto, streams, child_process, sqlite, ws, sab-native (cross-process SharedBuffer), terminal-native, and more
- 19 Web API packages — fetch, XMLHttpRequest, WebSocket, WebCrypto, WebRTC, WebAudio, Streams (BYOB), EventSource, AbortController, DOMParser, Gamepad
- 8 DOM / bridge packages — Canvas2D (Cairo), Canvas2D-core (headless), WebGL (OpenGL ES), DOM elements, event bridge, iframes (WebKit), video (gtk4paintablesink), bridge-types
- 3 Adwaita packages for browser targets — Web Components, Adwaita Sans fonts, symbolic icons
- 8 integration test suites — webtorrent, socket.io, streamx, Autobahn (RFC 6455 fuzzing), mcp-typescript-sdk, mcp-inspector-cli, axios, worker-stress
- Flatpak toolchain —
gjsify flatpak initscaffolds manifest + MetaInfo + .desktop + flathub.json from one config block;gjsify flatpak checkruns Flathub linters locally - Node-free CLI bootstrap —
curl … install.mjs | gjs -m -installs@gjsify/cliwithout npm/Node;gjsify self-update/gjsify uninstall -ground out the lifecycle - ESM-only, TypeScript-first, Rolldown-based build system
- Native GNOME library bindings:
Giofor I/O,Soup 3.0for HTTP,GLibfor crypto/process,Cairofor 2D,GTK 4for UI,GStreamerfor media + WebRTC,libgdafor SQLite,Manettefor gamepads,WebKitfor iframes,nghttp2for native HTTP/2 - Every unit test runs on both Node.js and GJS
Node-free bootstrap (recommended, requires only gjs ≥ 1.86 and curl):
curl -fsSL https://github.com/gjsify/gjsify/releases/latest/download/install.mjs \
-o /tmp/g.mjs && gjs -m /tmp/g.mjs && rm /tmp/g.mjsThis lays down @gjsify/cli under ~/.local/share/gjsify/global/ and a launcher
at ~/.local/bin/gjsify — no npm / node required on the machine. Run
gjsify self-update to refresh in place, or gjsify uninstall -g @gjsify/cli
to remove.
Optional Node-managed install (escape hatch — only needed if you already
manage CLIs through Node and want to install @gjsify/cli from npm):
gjsify install -g @gjsify/cli # once the CLI is bootstrapped
# or, from a Node-only machine:
npm install -g @gjsify/cligjsify create my-app
cd my-app
gjsify install --immutable
gjsify build
gjsify run startgjsify create scaffolds a GTK 4 application with TypeScript, ready to build
and run. gjsify install resolves and installs npm dependencies via the
committed Node-free dist/cli.gjs.mjs bundle — no npm / yarn invocation
required. Pass --immutable for reproducible CI installs (gjsify-lock.json must
match package.json).
The runtime requirement is GJS ≥ 1.86 (SpiderMonkey 140 / ES2024, ships with Fedora 43+ and Ubuntu 25.10+). Plus GNOME development libraries for the features you plan to use:
Fedora:
sudo dnf install gjs glib2-devel gobject-introspection-devel gtk4-devel \
libsoup3-devel webkitgtk6.0-devel libadwaita-devel gdk-pixbuf2-devel \
libepoxy-devel libgda libgda-sqlite meson vala gcc pkgconfUbuntu:
sudo apt install gjs libglib2.0-dev libgirepository1.0-dev libgtk-4-dev \
libsoup-3.0-dev libwebkitgtk-6.0-dev libadwaita-1-dev libgdk-pixbuf-2.0-dev \
libepoxy-dev libgda-6.0-dev meson valac gcc pkg-configNode.js 24+ is optional — needed only if you run the legacy test:node
cross-validation suites (every unit test is mirrored on Node + GJS) or if you
prefer to manage @gjsify/cli via npm install -g.
# Build a TypeScript file for GJS (default target)
gjsify build src/index.ts --outfile dist/app.js
# Run it (sets LD_LIBRARY_PATH + GI_TYPELIB_PATH for native @gjsify/* prebuilds)
gjsify run dist/app.js
# Try a published GJS app without installing it
gjsify dlx <pkg>gjsify generate-installer scaffolds an install.mjs for your package,
parameterised to your npm name and bin name:
cd my-gjs-app
gjsify generate-installer
git add install.mjs && git commit -m "chore: add gjsify-based installer"Users of your app then install with:
curl -fsSL https://github.com/<you>/<repo>/raw/main/install.mjs \
-o /tmp/i.mjs && gjs -m /tmp/i.mjs && rm /tmp/i.mjsNo npm / Node required on the user's machine.
gjsify flatpak init scaffolds the full Flathub asset set — manifest +
MetaInfo XML + .desktop + flathub.json — from one package.json
config block. --kind app (default) for GTK/Adwaita desktop apps;
--kind cli for headless tools.
gjsify flatpak init # generate everything
gjsify flatpak check # run appstreamcli + flatpak-builder-lint locally
gjsify flatpak build # wrap flatpak-builderSee the Flatpak app guide and Flatpak CLI guide for end-to-end submission.
Write standard Node.js code — the bundler resolves node:* imports to @gjsify/* implementations when targeting GJS:
import { readFileSync, writeFileSync } from 'node:fs';
import { join } from 'node:path';
import { createHash } from 'node:crypto';
const content = readFileSync('/etc/hostname', 'utf8');
const hash = createHash('sha256').update(content).digest('hex');
writeFileSync(join('/tmp', 'hostname-hash.txt'), hash);
console.log(`Hostname hash: ${hash}`);Web APIs work too:
const response = await fetch('https://api.github.com/zen');
const text = await response.text();
console.log(text);| Status | Packages |
|---|---|
| Full (36) | assert, async_hooks, buffer, child_process, console, constants, crypto, dgram, diagnostics_channel, dns, events, fs, globals, http, http2, https, module, net, os, path, perf_hooks, process, querystring, readline, stream, string_decoder, sys, timers, tls, tty, url, util, zlib + native: terminal-native, sab-native |
| Partial (5) | sqlite (libgda-backed subset), ws (no perMessageDeflate/ping-pong events), worker_threads (subprocess-based + cross-process SAB via sab-native), vm (eval-based, no realm isolation), v8 (stub) |
| Stub (3) | cluster, domain, inspector |
Plus @gjsify/node-polyfills meta package for scaffolding.
abort-controller, compression-streams, dom-events, dom-exception, domparser, eventsource, fetch, formdata, gamepad, web-globals, web-streams, webaudio, webcrypto, webrtc (+ webrtc-native Vala prebuild), websocket, webstorage, xmlhttprequest. Plus @gjsify/web-polyfills meta.
Adwaita for browser targets: adwaita-web, adwaita-fonts, adwaita-icons.
| Package | Backed by | Provides |
|---|---|---|
| canvas2d-core | Cairo, PangoCairo | Headless CanvasRenderingContext2D, CanvasGradient, CanvasPattern, Path2D, ImageData |
| canvas2d | canvas2d-core, Gtk 4 | Re-exports canvas2d-core + FontFace + Canvas2DBridge → Gtk.DrawingArea |
| dom-elements | GdkPixbuf, canvas2d-core | Node, Element, HTMLCanvasElement (auto-registers '2d'), HTMLImageElement, Document |
| event-bridge | GTK 4, Gdk 4 | GTK → DOM event mapping (Mouse, Pointer, Keyboard, Wheel, Focus) |
| iframe | WebKit 6.0 | HTMLIFrameElement, IFrameBridge → WebKit.WebView |
| video | Gst 1.0, Gtk 4 | HTMLVideoElement, VideoBridge → Gtk.Picture (gtk4paintablesink) |
| webgl | gwebgl (Vala) | WebGL 1.0/2.0, WebGLBridge → Gtk.GLArea |
| bridge-types | — | Shared BridgeEnvironment / BridgeWindow interfaces |
packages/
node/ # 42 Node.js API packages (@gjsify/<name>) + node-polyfills meta
web/ # 19 Web API packages (fetch, XHR, WebSocket, WebRTC, WebAudio, …) + web-polyfills meta
dom/ # 8 DOM / bridge packages (canvas2d-core, canvas2d, webgl, dom-elements, event-bridge, iframe, video, bridge-types)
gjs/ # GJS utilities, types, test framework (@gjsify/unit)
infra/ # Build tools, Rolldown / Vite plugins, CLI, create-app
examples/
dom/ # DOM-pillar examples (WebGL tutorials, WebRTC, WebTorrent, three.js, canvas2d, video, iframe, gamepad)
node/ # Node-pillar examples (Express, Hono, Koa, socket.io, SSE chat, WS chat, Deepkit, CLI tools)
showcases/
dom/ # Polished DOM showcases consumed by `gjsify showcase`
node/ # Polished Node showcases
tests/
e2e/ # End-to-end build/test runner
integration/ # Curated upstream test suites (webtorrent, socket.io, streamx, Autobahn)
refs/ # 59 read-only reference submodules (Node.js, Deno, Bun, WebKit, GStreamer, …)
# Install dependencies (workspace-wide, reproducible from gjsify-lock.json)
gjsify install --immutable
# Full build (every workspace package, in topological order)
gjsify foreach -A -t build
# Type check (all packages, parallel)
gjsify check
# Run all unit tests (every package's src/test.mts on GJS + Node, aggregated)
gjsify foreach -A test
# Run opt-in integration suites (webtorrent, socket.io, streamx, Autobahn)
gjsify workspace @gjsify/integration-webtorrent test
gjsify workspace @gjsify/integration-socket.io test
gjsify workspace @gjsify/integration-streamx test
gjsify workspace @gjsify/integration-autobahn test
# Per-package testing
cd packages/node/fs
gjsify test # Build + run src/test.mts on GJS and Node, aggregate
gjsify test --runtime gjs # Only the GJS run
gjsify test --runtime node # Only the Node run (test-correctness validation)gjsify test replaces the per-package build:test:{gjs,node} + test:{gjs,node}
script boilerplate: it locates src/test.mts, builds it in-process for each
requested runtime, runs each output, and aggregates exit codes. Add --rebuild
to force a rebuild or --no-build to run an already-built bundle.
Every test runs on both Node.js and GJS. Node.js validates test correctness; GJS validates the implementation. Tests use @gjsify/unit (describe/it/expect). Node.js is therefore required for development of the polyfills themselves, but not for downstream consumers — they only need GJS.
- GJS 1.86+ (SpiderMonkey 140 / ES2024) — runtime
- Node.js 24.x — optional, only for the cross-validation
test:nodetrack - Rolldown target:
firefox140 - ESM-only, TypeScript 6.x
See individual package licenses. Most packages are MIT.
