---
title: Quickstart: Node
description: Same route after the pinned Dawn and ORT setup.
---

# Quickstart: Node



In this quickstart you run the same integration in Node, with Dawn providing WebGPU. Node has no global WebGPU, so the recipe wires one up explicitly before ORT initializes — pin the versions below exactly; the combination is what vgpu validates.

The primary Node matrix is Node 22, `webgpu@0.4.0`, `onnxruntime-web@1.27.0`, and vgpu/software-renderer 0.1.6. The `webgpu@0.4.0` Linux ARM64 prebuilt requires glibc 2.38; run the primary recipe and generic-WASM negative proof on x64 CI or ARM64 with glibc 2.38 or newer. The explicitly labeled host fallback uses the supported `@vgpu/adapter-node` portable Dawn and software renderer. Executable recipes are under `experiments/ort-init-device/`.

If `require("webgpu")` fails with a `GLIBC_2.38` error, run `npx vgpu doctor` and follow its prescription: `npx vgpu install-dawn` installs vgpu's portable Dawn build (glibc 2.31 floor), and `npx vgpu install-software-renderer` adds a portable software renderer for hosts without a GPU. The recipes below run unchanged on that fallback.

## Node snapshot

Same route after the pinned Dawn and ORT setup:

```ts
import * as ort from "onnxruntime-web/webgpu";
import { create, globals } from "webgpu";
import { initFromDevice } from "vgpu/node";

declare const modelBytes: Uint8Array;
declare const input: ort.Tensor;
declare function createOrtSession(dawn: GPU, modelBytes: Uint8Array): Promise<ort.InferenceSession>;

Object.assign(globalThis, globals);
const dawn = create([]);
Object.defineProperty(globalThis, "navigator", { configurable: true, value: { gpu: dawn } });
const session = await createOrtSession(dawn, modelBytes);
const rawDevice = await ort.env.webgpu.device;
const gpu = await initFromDevice(rawDevice);
const output = (await session.run({ input })).output;
const destination = gpu.device.createBuffer({ size: output.gpuBuffer.size, usage: ["storage", "copy_dst"] });
try {
  const encoder = gpu.gpu.createCommandEncoder();
  encoder.copyBufferToBuffer(output.gpuBuffer, 0, destination.gpu, 0, output.gpuBuffer.size);
  gpu.gpu.queue.submit([encoder.finish()]);
  await gpu.device.queue.flush();
} finally {
  destination.dispose();
  output.dispose();
  gpu.dispose();
  await session.release();
}
```

## Node reference

Same zero-copy route on Node:

```ts
import * as ort from "onnxruntime-web/webgpu";
import { initFromDevice, type Buffer, type Compute } from "vgpu/node";

declare const session: ort.InferenceSession;
declare const input: ort.Tensor;
declare const compute: Compute;
declare const destination: Buffer;
declare const workgroups: number;

const rawDevice = await ort.env.webgpu.device;
const gpu = await initFromDevice(rawDevice);
const output = (await session.run({ input })).output;
const source = gpu.device.wrapBuffer(output.gpuBuffer);
try {
  compute.set({ source, destination }).dispatch(workgroups);
  await gpu.device.queue.flush();
} finally {
  source.dispose();
  output.dispose();
  gpu.dispose();
  await session.release();
}
```


---

For a semantic overview of all documentation, see [/sitemap.md](/sitemap.md)

For an index of all available documentation, see [/llms.txt](/llms.txt)

For agent-facing discovery, including API and MCP surfaces, see [/agents.md](/agents.md)