Skip to content

Overview

gjsify is a TypeScript framework for native desktop apps. You write TypeScript and you get a real GTK 4 / Adwaita application: one native process, no bundled browser engine, no second process behind the window. GTK and libadwaita stay exactly as they are, reached through gi:// imports.

Four JavaScript runtimes can run that app: GJS, Node.js, Bun and Deno. What differs between them is where gi:// comes from. GJS is GNOME’s own JavaScript runtime, so it resolves gi:// itself with nothing in between. Linux distributions ship it and Homebrew builds it for macOS, but there is no GJS for Windows. On Node, Bun and Deno the same imports resolve through @gjsify/node-gi, a Node-API addon, and that is the route reaching all three operating systems.

The code you write is the same either way. Where a runtime has no implementation of its own, gjsify supplies one: on GJS that means node:fs, fetch, WebSocket and <canvas>, backed by Gio, libsoup and Cairo, which is what lets a large slice of npm run there. Where the runtime already has the module, you get the runtime’s own.

What you can build. A desktop app with the full Adwaita widget set. A game rendering with WebGL into a real Gtk.GLArea or with Canvas 2D into a Gtk.DrawingArea, where three.js and Excalibur.js run unmodified. A command-line tool. An HTTP server on Express or Hono. gjsify create scaffolds a starter for each of those, and a bare Gtk.Window if you want to begin from nothing. Every one of them builds for all four runtimes, and the same source builds for the browser too.

The CLI runs on all four runtimes as well, so you develop with the one you already have.

Start here: Getting Started takes you from nothing to a window on screen.

Where your code runs is a flag on the build, not a decision baked into your app:

gjsify build --appRuns onWhat that gives you
gjsGJS, on Linux; macOS in partGNOME’s own interpreter resolves gi:// directly, with nothing bridging into GTK. Linux distributions ship the runtime. On macOS it comes from Homebrew and only part of it is verified there, and there is no gjs for Windows.
nodeNode.js, Bun and Deno, on Linux, macOS and WindowsOne bundle for all three, because Node-API is their common ABI. gi:// goes through @gjsify/node-gi, and @gjsify/gtk-runtime-darwin-arm64, -darwin-x64 and -win32-x64 carry GTK itself, so those two platforms need no system GTK.
browserany modern browserNo native code at all, so it is portable by construction. Adwaita comes over as Web Components through @gjsify/adwaita-web.
nativescriptAndroid and iOS, experimentalReal native views, no webview. @gjsify/adwaita-nativescript carries the widget set. Try it; do not ship on it yet. See Runtimes.

The flag defaults to whatever runtime is running the CLI, so a CLI installed through the GJS bootstrap builds gjs bundles and one installed with npm, Bun or Deno builds node ones. Override it per command with --app, or per project with gjsify.app in package.json. Runtimes covers what each target gives you; Platform Support answers the operating-system question.

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
  • Getting Started: scaffold a project, get a window on screen
  • Widget Gallery: every Adwaita component, with live previews and code
  • UI Frameworks: render a GTK window from Solid, Vue or React, or bring React Native code to it
  • Native Adwaita Apps: the app shell, navigation, dialogs and toasts
  • Runtimes: GJS, Node.js, Bun, Deno, the browser and mobile, and what runs where
  • Packages: the Node.js, Web and DOM APIs gjsify implements
  • Showcases: full apps that run natively and in your browser from one source
  • CLI Reference: every gjsify command and flag
  • How It Works: the build pipeline, if you want to look inside