npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

node-qemu

v1.2.0

Published

QEMU management library for Node.js

Readme

node-qemu

QEMU management library for Node.js

npm CI License

Typed QMP client, process lifecycle manager, and qemu-img wrappers - all in pure TypeScript with no native bindings.

Features

  • QMP client - typed JSON-RPC over Unix socket or TCP, full capability negotiation, sequential command dispatch, typed async events
  • 60+ typed QMP commands - VM control, block/storage, device hotplug, migration, CPU/memory, display, introspection, QOM
  • Process manager - spawn, monitor, and gracefully stop QEMU processes; PID files; stdout/stderr streams
  • CLI argument builder - convert a typed QemuConfig into a validated string[] argv
  • Image tools - typed wrappers around qemu-img: create, resize, convert, info, check, snapshots
  • AsyncDisposable - await using support on QMPClient and QemuProcess
  • Automatic reconnect - exponential backoff on unexpected disconnect (opt-in)
  • Dual ESM + CJS output, TypeScript source maps, full .d.ts declarations

Installation

npm install node-qemu

Requires Node.js ≥ 18 and qemu-system-* / qemu-img binaries on the host.

Quick Start

QMP Client

import { QMPClient } from "node-qemu";

await using client = new QMPClient({ socketPath: "/run/qemu/vm1.sock" });
await client.connect();

// Typed command
const status = await client.queryStatus();
console.log(status.status); // "running" | "paused" | ...

// Typed events
client.on("SHUTDOWN", (e) => console.log("Guest shut down:", e.reason));
client.on("BLOCK_JOB_COMPLETED", (e) => console.log("Backup done:", e.device));
client.on("MIGRATION", (e) => console.log("Migration:", e.status));

// Pause and resume
await client.stop();
await client.cont();

// Graceful shutdown
await client.systemPowerdown();

Process Manager

import { QemuProcess, QMPClient } from "node-qemu";

const proc = new QemuProcess({
  binary: "/usr/bin/qemu-system-x86_64",
  config: {
    machine: { type: "q35", accel: "kvm" },
    cpu: "host",
    memory: { size: 2048 },
    drives: [{ file: "/var/lib/qemu/vm1.qcow2", format: "qcow2", virtio: true }],
    net: [{ type: "tap", ifname: "tap0", script: "no", vhost: true }],
    qmp: { socketPath: "/run/qemu/vm1.sock" },
    vnc: { display: "0" },
    enableKvm: true,
    noReboot: true,
    pidfile: "/run/qemu/vm1.pid",
  },
});

await proc.start();
console.log("QEMU PID:", proc.pid);

proc.on("stderr", (line) => console.error("[qemu]", line));
proc.on("exit", (code, signal) => console.log("Exited", { code, signal }));

// Connect QMP after process starts
await using client = new QMPClient({ socketPath: proc.socketPath! });
await client.connect();

// Graceful stop - SIGTERM with 5s SIGKILL fallback
await proc.stop();

Image Tools

import { QemuImg } from "node-qemu";

// Create a thin-provisioned overlay over a base image
await QemuImg.create({
  filename: "/var/lib/qemu/vm1.qcow2",
  format: "qcow2",
  size: "20G",
  backingFile: "/var/lib/qemu/base.qcow2",
});

// Resize in place
await QemuImg.resize({ filename: "/var/lib/qemu/vm1.qcow2", size: "+10G" });

// Convert raw → qcow2 with compression
await QemuImg.convert({
  src: "/var/lib/qemu/vm1.raw",
  dst: "/var/lib/qemu/vm1.qcow2",
  format: "qcow2",
  compress: true,
});

// Inspect
const info = await QemuImg.info({ filename: "/var/lib/qemu/vm1.qcow2" });
console.log(info.format, info.virtualSize, info.backingFile);

// Internal qcow2 snapshots
await QemuImg.snapshotCreate({ filename: "/var/lib/qemu/vm1.qcow2", tag: "clean" });
const snaps = await QemuImg.snapshotList({ filename: "/var/lib/qemu/vm1.qcow2" });
await QemuImg.snapshotApply({ filename: "/var/lib/qemu/vm1.qcow2", tag: "clean" });
await QemuImg.snapshotDelete({ filename: "/var/lib/qemu/vm1.qcow2", tag: "clean" });

TCP Connection

const client = new QMPClient({ host: "192.168.1.10", port: 4444 });
await client.connect();

Automatic Reconnect

const client = new QMPClient({
  socketPath: "/run/qemu/vm1.sock",
  reconnect: true,
  reconnectDelay: 1000,    // initial delay ms (doubles on each attempt)
  reconnectMaxDelay: 30_000,
});

client.on("disconnected", () => console.log("Lost connection, retrying..."));
client.on("connected", () => console.log("Reconnected"));

Incremental Backup with Dirty Bitmaps

// Track changed blocks since last backup
await client.blockDirtyBitmapAdd({ node: "hd0", name: "inc-backup" });

// ... time passes, guest writes data ...

// Incremental backup using the bitmap
await client.blockdevBackup({
  device: "hd0",
  target: "backup-target",
  sync: "incremental",
  bitmap: "inc-backup",
});

// Monitor completion
client.once("BLOCK_JOB_COMPLETED", async (e) => {
  console.log("Backup complete:", e.device);
  await client.blockDirtyBitmapClear({ node: "hd0", name: "inc-backup" });
});

Live Migration

await client.migrateSetCapabilities([
  { capability: "xbzrle", state: true },
  { capability: "zero-blocks", state: true },
]);

await client.migrate({ uri: "tcp:192.168.1.2:4444" });

client.on("MIGRATION", (e) => {
  if (e.status === "completed") console.log("Migration done");
  if (e.status === "failed")    console.error("Migration failed");
});

Error Handling

import { QmpError, QmpCommandError } from "node-qemu";

try {
  await client.blockdevBackup({ device: "hd0", target: "missing", sync: "full" });
} catch (err) {
  if (err instanceof QmpCommandError) {
    console.error(err.qmpClass, err.description); // "DeviceNotFound" "..."
  } else if (err instanceof QmpError) {
    console.error(err.code); // "CONNECTION_CLOSED" | "CLIENT_CLOSED" | ...
  }
}

Events

QMPClient extends EventEmitter with fully typed payloads:

| Event | Payload | Description | |---|---|---| | SHUTDOWN | ShutdownEvent | Guest or host-initiated shutdown | | RESET | ResetEvent | System reset | | STOP | - | VM execution paused | | RESUME | - | VM execution resumed | | GUEST_PANICKED | GuestPanicEvent | Guest kernel panic | | WATCHDOG | WatchdogEvent | Watchdog timer fired | | BLOCK_IO_ERROR | BlockIoErrorEvent | Block device I/O error | | BLOCK_JOB_COMPLETED | BlockJobEvent | Backup/mirror/stream finished | | BLOCK_JOB_CANCELLED | BlockJobEvent | Block job cancelled | | BLOCK_JOB_ERROR | BlockJobErrorEvent | Block job I/O error | | BLOCK_JOB_READY | BlockJobEvent | Mirror ready to pivot | | JOB_STATUS_CHANGE | JobStatusChangeEvent | Generic job status changed | | DEVICE_ADDED | DeviceEvent | Hotplug device added | | DEVICE_DELETED | DeviceEvent | Hotplug device removed | | MIGRATION | MigrationEvent | Migration status update | | MIGRATION_PASS | MigrationPassEvent | Migration pass counter | | NIC_RX_FILTER_CHANGED | NicRxFilterEvent | NIC RX filter updated | | VNC_CONNECTED | VncEvent | VNC client connected | | VNC_DISCONNECTED | VncEvent | VNC client disconnected | | MEMORY_FAILURE | MemoryFailureEvent | Hardware memory failure | | SUSPEND | - | Guest suspended | | WAKEUP | - | Guest woke up | | connected | - | QMP handshake complete | | disconnected | - | Socket closed | | error | Error | Transport error |

API Reference

Full API documentation is available at sourceregistry.github.io/node-qemu.

For the underlying QMP wire protocol, see the QEMU QMP Reference and qemu-img manual.

Related Libraries

| Library | Role | |---|---| | node-lxc | LXC container lifecycle | | node-ovsdb | Open vSwitch / OVSDB networking | | node-qemu | QEMU VM lifecycle (this library) |

License

Apache-2.0