Skip to content

GJSify

Node.js & Web APIs,
running on GJS

Bring the full TypeScript ecosystem to GJS: fs, net, http, fetch, WebSocket, Canvas2D, WebGL and more, all running natively on Linux.

Terminal
$ gjs -m express-webserver.js
Express.js blog running on GJS
Local: http://localhost:3000/
API: http://localhost:3000/api/posts
Press Ctrl+C to stop
[12:34:56] GET /
[12:34:56] GET /style.css
[12:34:56] GET /app.js
[12:34:56] GET /api/runtime
[12:34:56] GET /api/posts
express-webserver.ts
import '@gjsify/node-globals';
import express from 'express';
import { posts } from './data/posts.js';
const app = express();
app.use(express.json());
app.get('/api/posts', (_req, res) => {
res.json({ count: posts.length, posts });
});
app.get('/api/posts/:slug', (req, res) => {
const post = posts.find((p) => p.slug === req.params.slug);
if (!post) return res.status(404).json({ error: 'Not found' });
res.json(post);
});
app.use(express.static('public'));
app.listen(3000, () => {
console.log('Express server running at http://localhost:3000');
});
Full example →
Terminal
npx @gjsify/cli showcase express-webserver
pixel-demo.ts
import Adw from 'gi://Adw?version=1';
import { WebGLBridge } from '@gjsify/webgl';
import * as THREE from 'three';
import { RenderPixelatedPass } from 'three/addons/postprocessing/RenderPixelatedPass.js';
import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js';
const app = new Adw.Application({ application_id: 'gjsify.examples.pixel' });
app.connect('activate', () => {
const glArea = new WebGLBridge();
glArea.onReady((canvas) => {
const renderer = new THREE.WebGLRenderer({ canvas });
const scene = new THREE.Scene();
const camera = new THREE.OrthographicCamera();
const composer = new EffectComposer(renderer);
composer.addPass(new RenderPixelatedPass(6, scene, camera));
});
});
Full example →
Terminal
npx @gjsify/cli showcase three-postprocessing-pixel
teapot-demo.ts
import Adw from 'gi://Adw?version=1';
import { WebGLBridge } from '@gjsify/webgl';
import * as THREE from 'three';
import { TeapotGeometry } from 'three/addons/geometries/TeapotGeometry.js';
const app = new Adw.Application({ application_id: 'gjsify.examples.teapot' });
app.connect('activate', () => {
const glArea = new WebGLBridge();
glArea.onReady((canvas) => {
const renderer = new THREE.WebGLRenderer({ canvas });
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(45);
scene.add(new THREE.Mesh(
new TeapotGeometry(50, 20),
new THREE.MeshPhongMaterial({ color: 0xc0c0c0 })
));
});
});
Full example →
Terminal
npx @gjsify/cli showcase three-geometry-teapot
jelly-jumper.ts
import Adw from 'gi://Adw?version=1';
import { WebGLBridge } from '@gjsify/webgl';
import * as ex from 'excalibur';
import { startGame } from './game.js';
const app = new Adw.Application({
application_id: 'gjsify.examples.jelly-jumper',
});
app.connect('activate', () => {
const glArea = new WebGLBridge();
glArea.onReady(async (canvas) => {
const game = await startGame(canvas);
// game.mute(); // toggle audio
// game.pause(); // toggle pause
});
});
Full example →
Terminal
npx @gjsify/cli showcase excalibur-jelly-jumper
fireworks.ts
import Adw from 'gi://Adw?version=1';
import { Canvas2DBridge } from '@gjsify/canvas2d';
import { start } from './fireworks.js';
const app = new Adw.Application({ application_id: 'gjsify.examples.fireworks' });
app.connect('activate', () => {
const canvasWidget = new Canvas2DBridge();
canvasWidget.installGlobals();
canvasWidget.onReady((canvas) => {
const demo = start(canvas);
// demo.effectController.particleCount = 60;
// demo.effectController.autoInterval = 150;
});
});
Full example →
Terminal
npx @gjsify/cli showcase canvas2d-fireworks

Get started in seconds

Terminal
$ npx @gjsify/cli create my-app

or run npx @gjsify/cli --help to explore all commands

What makes gjsify different

Three worlds, one runtime

GNOME, Node.js, and the Web have lived in separate runtimes for a decade. gjsify dissolves the boundary — every API lands inside one SpiderMonkey process and shares the same memory, the same event loop, the same GTK main context.

For example

Ship a browser game engine — without shipping a browser.

Excalibur.js renders directly into a Gtk.GLArea through gjsify's WebGL bridge. Pointer, keyboard, and gamepad input flows through GTK4 event controllers, dispatched as W3C DOM events. Audio runs on GStreamer through the Web Audio API. The whole game lives in one process — the same one that draws the Adwaita window around it. No WebKit.WebView, no IPC bridge, no embedded Chromium.

Electron app ~150 MB Chromium runtime · separate renderer process · webContents bridge · X11/Wayland double-buffered
gjsify app Stock GJS · single process · native GTK4 widgets · uses the GNOME runtime the user already has installed

Project Coverage

116 of 119 pillar entries implemented

Every category in STATUS.md's summary table, rendered as a live progress bar. The data file is regenerated from STATUS.md on every build, so the bars never lag behind reality.

97% 109 full 7 partial 3 stub
Node.js modules 38 / 41 (93%)
Web API packages 18 / 18 (100%)
Adwaita assets 3 / 3 (100%)
DOM 2 / 2 (100%)
Framework bridges 6 / 6 (100%)
GJS infra 3 / 3 (100%)
Build / infra tools 16 / 16 (100%)
Showcases 8 / 8 (100%)
Integration test suites 22 / 22 (100%)

Web Platform Coverage

34 of 59 web standards

Coverage of relevant W3C and WHATWG standards, including 10 APIs that are explicitly out of scope for desktop GTK apps (Service Worker, FS Access, Web Bluetooth, …).

58% 32 full 2 partial 15 planned 10 out of scope
Networking 5 / 5
  • Fetch @gjsify/fetch Full
  • XMLHttpRequest @gjsify/xmlhttprequest Full
  • WebSocket @gjsify/websocket Full
  • Server-Sent Events @gjsify/eventsource Full
  • WebRTC @gjsify/webrtc Full
Storage 1 / 5
  • Web Storage @gjsify/webstorage localStorage + sessionStorage Full
  • IndexedDB libgda could back Planned
  • Cookie Store API Planned
  • Cache API Service Worker companion Out of scope
  • Origin Private File System Browser sandbox; GTK uses Gio.File directly Out of scope
Streams & Encoding 5 / 5
  • Streams (Readable/Writable/Transform) @gjsify/streams Full
  • Queuing Strategies @gjsify/streams Full
  • Compression Streams @gjsify/compression-streams Full
  • Encoding (TextEncoder/Decoder) @gjsify/globals Full
  • TextEncoderStream / TextDecoderStream @gjsify/streams Full
Crypto 1 / 1
  • Web Crypto @gjsify/webcrypto Full
Events & Async 4 / 5
  • DOM Events (Event/EventTarget/CustomEvent) @gjsify/dom-events Full
  • DOMException @gjsify/dom-exception Full
  • AbortController / AbortSignal @gjsify/abort-controller Full
  • Channel Messaging (MessageChannel) @gjsify/message-channel Full
  • Prioritized Task Scheduling scheduler.postTask — GLib idle could back Planned
Workers 2 / 4
  • Web Workers @gjsify/worker_threads file-based; no DOM-Worker shim Partial
  • BroadcastChannel @gjsify/worker_threads Full
  • SharedWorker Browser multi-tab concept Out of scope
  • Service Workers HTTP cache proxy — irrelevant for GTK apps Out of scope
Multimedia 4 / 7
  • Web Audio @gjsify/webaudio Phase 1: AudioContext + Source + Gain Partial
  • MediaDevices / getUserMedia @gjsify/webrtc Full
  • Canvas 2D @gjsify/canvas2d-core Full
  • WebGL / WebGL2 @gjsify/webgl Full
  • MediaRecorder GStreamer encodebin could back Planned
  • WebGPU no GNOME backend yet — multi-year effort Planned
  • Web MIDI Native apps use ALSA/JACK directly Out of scope
DOM & UI 4 / 8
  • DOM (Document/Element/Node) @gjsify/dom-elements Full
  • HTML Elements (HTMLElement family) @gjsify/dom-elements Full
  • DOMParser @gjsify/domparser Full
  • Mutation/Resize/IntersectionObserver @gjsify/dom-elements Full
  • Custom Elements + Shadow DOM Needed for Adwaita component composition Planned
  • XMLSerializer Planned
  • View Transitions Browser render-pipeline specific Out of scope
  • Web Animations API Planned
Input & Devices 2 / 5
  • Pointer/Mouse/Keyboard Events @gjsify/dom-events Full
  • Gamepad @gjsify/gamepad Full
  • Pointer Lock Gdk.Seat.grab could back Planned
  • Web Bluetooth GTK apps use BlueZ directly Out of scope
  • Web USB / Serial / HID / NFC Native apps use libusb/udev directly Out of scope
Files & Data 3 / 5
  • Blob / File @gjsify/buffer Full
  • FormData @gjsify/formdata Full
  • URL / URLSearchParams @gjsify/url Full
  • FileReader Trivial via Blob+streams Planned
  • File System Access API GTK uses Gio.File directly Out of scope
Performance & Compute 3 / 3
  • Performance API @gjsify/perf_hooks Full
  • WebAssembly @gjsify/webassembly Full
  • structuredClone @gjsify/globals Full
Notifications, Geo, Permissions 0 / 3
  • Notifications API Gio.Notification candidate Planned
  • Geolocation GeoClue2 + consent dialog Planned
  • Permissions API Planned
Modern / Experimental 0 / 3
  • Web Locks GLib.Mutex async wrapper Planned
  • URLPattern Planned
  • Background Sync / Push Service Worker tier Out of scope

Node.js API Coverage

38 of 41 Node.js modules

User-facing Node modules backed by GLib, Gio, Soup, and native Vala bridges. 3 deprecated or browser-irrelevant modules ship as stubs so dependency checks resolve.

93% 33 full 5 partial 3 stub
I/O & Filesystem 4 / 4
  • fs Gio Full
  • path Full
  • url GLib.Uri Full
  • querystring Full
Networking 8 / 8
  • net Gio.Socket Full
  • dgram Gio.Socket UDP Full
  • dns Gio.Resolver Full
  • http Soup 3.0 Server + ClientRequest + Agent Full
  • https Soup 3.0 Full
  • http2 Soup 3.0 h2 via ALPN; pushStream/respondWithFD/respondWithFile via @gjsify/http2-native (libnghttp2) Full
  • tls Gio.TlsConnection Full
  • ws @gjsify/websocket npm ws drop-in; Autobahn 510 OK / 0 FAIL Partial
Streams & Buffers 4 / 4
  • stream Full
  • buffer Blob/File Full
  • string_decoder Full
  • zlib Web Compression API Full
Crypto 1 / 1
  • crypto GLib.Checksum + Hmac Full
Concurrency 3 / 4
  • events Full
  • worker_threads Gio.Subprocess + @gjsify/sab-native Cross-process IPC, file-based workers Partial
  • async_hooks Full
  • cluster Stub
Process & OS 6 / 6
  • process GLib Full
  • os GLib Full
  • child_process Gio.Subprocess Full
  • tty GjsifyTerminal (Vala) Full
  • globals Full
  • module Full
Diagnostics & Utilities 9 / 11
  • util Full
  • console Full
  • assert Full
  • perf_hooks Full
  • diagnostics_channel Full
  • readline Full
  • timers GLib-source-safe (GLib.timeout_add) Full
  • constants Full
  • sys Deprecated alias for util Full
  • inspector Stub
  • domain Deprecated by Node Stub
Storage 1 / 1
  • sqlite Gda 6.0 (SQLite provider) Partial
Compute 2 / 2
  • vm runInThisContext via eval; no realm isolation Partial
  • v8 Wire-format v15 serialize/deserialize; no heap snapshot or CPU profile Partial

DOM ↔ GTK Bridges

Standard DOM elements, rendered natively

App code uses standard HTML elements. Each bridge translates the DOM lifecycle to a GTK widget — Cairo for 2D, OpenGL via libepoxy for WebGL, GStreamer for video, WebKit for iframes.

HTMLCanvasElement (2D) Gtk.DrawingArea

@gjsify/canvas2d Cairo + PangoCairo

HTMLCanvasElement (WebGL/WebGL2) Gtk.GLArea

@gjsify/webgl Vala/gwebgl + libepoxy

HTMLIFrameElement WebKit.WebView

@gjsify/iframe WebKit 6.0

HTMLVideoElement Gtk.Picture

@gjsify/video GStreamer + gtk4paintablesink

Native Vala bridges

Terminal @gjsify/terminal-native

Posix.isatty + ioctl TIOCGWINSZ + termios for @gjsify/tty

Shared ArrayBuffer @gjsify/sab-native

Cross-process shared memory + futex atomics for @gjsify/worker_threads

TLS @gjsify/tls-native

Direct OpenSSL access for @gjsify/tls

HTTP-Soup @gjsify/http-soup-bridge

Native Soup integration helpers for @gjsify/http

HTTP/2 @gjsify/http2-native

nghttp2 bridge for h2c, push streams, flow control

WebRTC @gjsify/webrtc-native

GLib.Idle signal marshalling for webrtcbin's streaming-thread callbacks

Integration Tests

21 npm packages, end-to-end

Real-world libraries whose own test suites (or a curated subset) run unmodified against @gjsify/*. Catches regressions that polyfill-internal tests would miss.

Parsing

acorn minify-xml gettext-parser

Build tooling

deepkit-type-compiler rolldown-native GJS rollup-pluginutils lightningcss ts-for-gir

Filesystem

fast-glob pkg-types cosmiconfig

Process & CLI

execa yargs

Networking

axios socket.io autobahn mcp-typescript-sdk mcp-inspector-cli

Streams & workers

streamx worker-stress

Peer-to-peer

webtorrent