CLI tool
sidorares/node-x11 avatar
sidorares/node-x11

node-x11: an X11 protocol client for Node.js, from core requests to DRI3

sidorares/node-x11 is an open-source project for practical engineering and operations.

536 stars75 forksJavaScriptMIT

At a glance

What is it?
node-x11 implements the X11 wire protocol in JavaScript, with optional GPU direct rendering through DRI3 and Present. It suits people writing window managers, remote desktop clients and protocol tooling in Node, not people who want a widget toolkit.
Who is it for?
Adopt node-x11 if you are writing protocol-level X11 code in JavaScript: a window manager, a compositor, a VNC or remote desktop client, or test tooling that drives a display. Do not adopt it if you want ready-made widgets, since the README points to ntk as the higher level toolkit built on top, and do not expect a small API surface, because the client exposes raw requests such as CreateWindow and AllocID.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 5 days ago.
What is it written in?
Mainly JavaScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 25, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The gap node-x11 fills: raw X11 from JavaScript

Most JavaScript desktop code sits far above the X11 protocol. Electron, GTK bindings and similar layers give you widgets and windows and hide the request stream entirely. node-x11 goes the other way. The package describes itself as "a pure node.js JavaScript client implementing X Window (X11) protocol and extensions", and that is the whole product: a client that speaks the protocol, plus a set of extensions, so that JavaScript code can allocate window IDs, create and map windows, select event masks and read replies. The audience is narrow and specific. The README's "In use" list names ntk (a higher level toolkit built on top), a media center controller, two tiling window managers, a VNC client, EWMH helpers, a Unity global menu client, a PDF viewer, a port of TinyWM, and a LiveScript window manager. Every one of those projects needs protocol access, not widgets. If you are writing a compositor, an automated test harness for an X server, or a remote desktop client, the protocol layer is the point. If you want a button, this is the wrong dependency.

How the client is structured: requests, IDs and event masks

The connection model is callback based. Calling createClient yields a display object; display.client is the protocol client and display.screen[0].root is the root window of the first screen. Window IDs are not allocated by the server on demand, they come from X.AllocID(), which mirrors the X11 resource ID model. Requests such as CreateWindow take the ID, the parent, geometry, and an options object that carries the event mask. The README's example combines Exposure and PointerMotion from x11.eventMask before creating the window, which is the standard X11 pattern: you declare which events you want delivered at creation time. Extension support is broad on paper. The README lists core X11 plus Xrender, Damage, Composite, Big-Requests, Dpms, Screensaver, XFixes, Shape, XTest, XC-Misc, GLX, DRI3, Present and Apple-WM. Two transport details stand out. First, DISPLAY strings accept a pluggable protocol prefix through x11.registerDisplayProtocol(name, connect), so myproto/host:0 can resolve to a custom connector. Second, createClient({ stream }) accepts any duplex stream, which is what lets the same client run in a browser. The README states that the documentation site's playground runs ordinary node-x11 code in the browser against a pure-JavaScript X server shipped in lib/xserver, including OpenGL through GLX-over-WebGL. The direct rendering path is documented separately: GPU frames as dma-buf pixmaps via DRI3 and Present, with details in docs/ext/dri3.md.

Installing node-x11 and creating your first window

Installation is a single npm command. The package name is x11, not node-x11, and the engines field in package.json requires Node 18 or newer.

bash
npm install x11

On Windows the README does not offer a native path. It instructs you to install XMing or Cygwin/X first and then obtain a copy of node-x11 via git or from GitHub, so the client is talking to an X server that lives outside Windows itself.

The smallest real program connects, allocates a window ID, creates a 500 by 500 window on the root window, selects exposure and pointer motion events, and maps it:

js
const x11 = require('x11');
const { Exposure, PointerMotion } = x11.eventMask;

x11.createClient((err, display) => {
  if (err) return console.log(err);
  const X = display.client;
  const root = display.screen[0].root;
  const wid = X.AllocID();
  X.CreateWindow(wid, root, 0, 0, 500, 500, 0, 0, 0, 0, {
    eventMask: Exposure | PointerMotion
  });
  X.MapWindow(wid);
});

Run it against a live DISPLAY and you should see an empty window appear; the callback fires once the connection is established, and the window is drawn by the server, not by your code. If nothing appears, the failure is almost always the display connection rather than the request sequence, which is why the example checks err before touching display. The repository also carries runnable material under examples/, including simple/, screenshot.js, xprop.js, windowmanager/, opengl/, dri3/, vncviewer/ and tetris.js, plus a smoketest directory. Those files are the practical next step after the snippet above, since the README itself stops mid-example.

Where node-x11 stops being the right tool

The README is honest about being a protocol client and silent about almost everything else. There is no layout engine, no widget set, no input method handling, no theming and no accessibility layer. Anything resembling an application framework has to be built or borrowed, which is exactly why the README points at ntk as a higher level toolkit on top of X11 rather than presenting node-x11 as an application library. The extension list is also a claim about implemented modules, not a compatibility guarantee against every X server in the field; the README does not document per-extension maturity, version negotiation or which extensions fail gracefully on a server that lacks them. The example in the README is truncated mid-statement, ending at display.scr, so the canonical first program is not complete in the file most people read first. Windows support depends on a third-party X server being installed and running. And the browser story, while real, is not a way to talk to a remote X server from a web page: it works because the package ships a pure-JavaScript X server in lib/xserver and the playground connects to that. Anyone expecting a general browser-to-X11 bridge will be disappointed. Finally, the API is deliberately low level. AllocID, CreateWindow and manual event masks are the normal vocabulary, and there is no promise wrapper; if you dislike callback style and manual ID management, this will feel like writing C in JavaScript.

Alternatives and the real difference in approach

The README's own comparison list is the best guide, and the contrast is mostly about language and binding style. XCB and XLib are the C implementations: XCB generates its API from the protocol description XML, which gives it a mechanically complete and consistent surface, while node-x11 is hand-shaped JavaScript with a callback API and explicit ID allocation. Python's python-xlib is the closest analogue in spirit, a pure-language client rather than a binding to C, and it has been around far longer; the difference for a JavaScript team is simply the runtime. Go's xgb is a pure Go implementation of the same idea, and Emacs Lisp's xelb is generated from the XCB XML, so it inherits that generation approach. If your project already lives in Node and needs to drive a display or speak to an X server, none of these alternatives remove the language mismatch, and that mismatch is the entire reason node-x11 exists. If your project is a C application, XCB is the more conventional choice and the generated API will be more predictable. If you want widgets rather than protocol, ntk on top of node-x11, or a toolkit outside this family entirely, is the correct layer.

Bun, file descriptors and the maintenance picture

Two operational details matter more than they first appear. The README states that node-x11 runs under Bun, including the parts that pass file descriptors over the connection, naming MIT-SHM segments and DRI3 buffers. Under Bun, the README says descriptors can also be received, and points to the "Running under Bun" section of docs/README.md. That is a meaningful difference from the Node path and worth reading before planning a Bun deployment. The direct rendering path itself is a separate document, docs/ext/dri3.md, which covers GPU frames as dma-buf pixmaps via DRI3 and Present. Neither of those documents is summarized in the README, so the README alone is not enough to judge whether the rendering path fits your environment. On maintenance, the repository is not archived, and the last push was on 2026-08-27, the same date as the v4.1.0 release; v4.0.1 and v4.0.0 landed on 2026-08-23. The package.json in the repository shows version 4.2.1, and the release notes list v4.1.0 as the most recent tagged release, so the repository manifest and the published tags are not perfectly in step. The project uses release-please (.release-please-manifest.json, release-please-config.json) and a Changelog.md, and the test scripts are split: npm test runs test-runner.js, with separate mocha targets for glx-emu and xserver, a Bun target, and a local script. That layout suggests the test surface is broad, but the README does not state a support policy, a deprecation process or a compatibility matrix for X servers. Upgrade cost is therefore hard to estimate from the README alone; Changelog.md and the release notes are where that has to be checked.

Licence and what it means for shipping

The package is MIT licensed, stated both in the repository's LICENSE file and in the licenses field of package.json. MIT is permissive: it allows use in closed-source products, modification and redistribution, provided the copyright notice and permission notice are preserved. For a library that gets bundled into a desktop application or an internal tool, that is about as light an obligation as you will find, and it does not impose the source-disclosure requirements that copyleft licences do. Two caveats belong here rather than in a legal opinion. First, node-x11 is a client for the X11 protocol; the X server you connect to, and any extensions such as GLX or DRI3, come from your operating system distribution and carry their own licences, which MIT on this package does nothing to change. Second, the README links to XMing and Cygwin/X for Windows users, and those are separate projects with separate terms. This is a description of what the licence text says, not legal advice; if you are shipping a product, have counsel review the actual LICENSE file rather than this paragraph.

Editorial conclusion

Adopt node-x11 if you are writing protocol-level X11 code in JavaScript: a window manager, a compositor, a VNC or remote desktop client, or test tooling that drives a display. Do not adopt it if you want ready-made widgets, since the README points to ntk as the higher level toolkit built on top, and do not expect a small API surface, because the client exposes raw requests such as CreateWindow and AllocID. Before committing, check that your target extensions are implemented rather than only listed, confirm your Node version satisfies the engines field of at least 18, and read docs/ext/dri3.md if your rendering path goes through dma-buf pixmaps.

Frequently asked questions

What is X11, and how does node-x11 relate to it?

X11 is the X Window System protocol that Unix-like desktops use to draw windows and deliver input. node-x11 is a pure JavaScript client that implements that protocol plus extensions such as Xrender, Damage, Composite, GLX, DRI3 and Present, so Node code can issue X11 requests directly.

How do I install X11 for use with node-x11?

The package itself installs with npm install x11. On Windows the README does not provide a native X server; it tells you to install XMing or Cygwin/X and then get a copy of node-x11 via git or from GitHub.

What Node.js version does node-x11 require?

The engines field in package.json specifies node >=18, so Node 18 or newer is required. The README also states that the package runs under Bun, including the parts that pass file descriptors over the connection.

Can node-x11 run in a browser?

Yes, with a caveat. The README says the client runs in browsers because DISPLAY strings accept a pluggable protocol prefix and createClient accepts any duplex stream. The documentation site's playground works by connecting to a pure-JavaScript X server shipped in lib/xserver, not to a remote X server.

Is node-x11 a widget toolkit?

No. It exposes protocol-level requests such as AllocID, CreateWindow and MapWindow with manual event masks. The README points to ntk as a higher level toolkit built on top of X11 for that kind of work.

Official sources

  1. Official documentation
  2. Official README
  3. Project repository
  4. Release notes
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/sidorares-node-x11.svg)](https://hysenlabs.com/projects/sidorares-node-x11)