# How to Use WebGPU in Deno: A Complete Guide to GPU Computing

> Learn to use WebGPU in Deno for powerful GPU computing and rendering. This guide covers the unstable navigator.gpu API and its setup.

- Repository: [Deno/deno](https://github.com/denoland/deno)
- Tags: how-to-guide
- Published: 2026-02-26

---

**WebGPU in Deno is available as an unstable extension that exposes the browser-standard `navigator.gpu` API through the `deno_webgpu` crate, requiring the `--unstable` flag to enable GPU compute and rendering capabilities.**

Deno implements the WebGPU specification as an unstable extension called `deno_webgpu`, allowing developers to leverage GPU acceleration for compute and graphics workloads directly in TypeScript. This implementation mirrors the browser's WebGPU API, exposing the familiar `navigator.gpu` interface while providing additional Deno-specific capabilities like backend selection and trace capture. The source code resides in the `denoland/deno` repository under the `ext/webgpu` directory.

## Enabling WebGPU in Deno

Because the API remains **unstable**, you must launch Deno with the `--unstable` flag to access WebGPU functionality.

```bash
deno run --unstable your_script.ts

```

When you first access `navigator.gpu`, Deno automatically lazy-loads the WebGPU module. For explicit control over initialization, import the lazy loader directly from the internal extension path:

```typescript
import { loadWebGPU } from "ext:deno_webgpu/00_init.js";

await loadWebGPU(); // Ensures the WebGPU module is available

```

## Architecture of WebGPU in Deno

The WebGPU implementation in Deno follows a layered architecture that bridges the Rust-based `wgpu` library with JavaScript APIs.

### Rust Operations Layer

At the core, [`ext/webgpu/lib.rs`](https://github.com/denoland/deno/blob/main/ext/webgpu/lib.rs) registers the WebGPU ops and creates the global `GPU` object. The `op_create_gpu` operation (lines 64-78) builds a GC-rooted `GPU` instance and stores helper globals for event handling. When you call `gpu.requestAdapter()`, the Rust side creates a `wgpu` `Adapter` and returns a wrapped `GPUAdapter` JavaScript object, honoring the `DENO_WEBGPU_BACKEND` environment variable for backend selection.

### JavaScript Bindings Layer

The file [`ext/webgpu/01_webgpu.js`](https://github.com/denoland/deno/blob/main/ext/webgpu/01_webgpu.js) provides the WebIDL-generated classes (e.g., `GPU`, `GPUAdapter`, `GPUDevice`) and registers error classes. It wires the Rust ops to JavaScript prototype methods and defines the `denoNsWebGPU` namespace for low-level capture operations like `deviceStartCapture` and `deviceStopCapture`.

### Lazy Loading Mechanism

The [`ext/webgpu/00_init.js`](https://github.com/denoland/deno/blob/main/ext/webgpu/00_init.js) file exposes a `loadWebGPU` function that implements lazy initialization. This matches the browser's pattern where `navigator.gpu` is only instantiated upon first access, improving startup performance for scripts that do not require GPU resources.

## Configuring the WebGPU Backend

Deno allows you to control the underlying GPU backend through environment variables, providing flexibility for different hardware and debugging scenarios.

Set `DENO_WEBGPU_BACKEND` to force a specific backend implementation:

```bash

# Force Vulkan on Linux or Windows

DENO_WEBGPU_BACKEND=vulkan deno run --unstable my_app.ts

# Force DirectX 12 on Windows

DENO_WEBGPU_BACKEND=dx12 deno run --unstable my_app.ts

```

The backend selection logic resides in [`ext/webgpu/lib.rs`](https://github.com/denoland/deno/blob/main/ext/webgpu/lib.rs) around line 60, where `std::env::var("DENO_WEBGPU_BACKEND")` is parsed into a `wgpu` `Backends` bit-mask.

For debugging, enable tracing with `DENO_WEBGPU_TRACE` to write `wgpu` trace files to a specified directory:

```bash
DENO_WEBGPU_TRACE=./trace deno run --unstable my_app.ts

```

## Practical WebGPU Examples in Deno

### Hello Triangle Rendering

The following example demonstrates a complete rendering pipeline using WebGPU in Deno, including shader loading and canvas configuration:

```typescript
// hello_triangle.ts
await import("ext:deno_webgpu/00_init.js"); // Optional if using --unstable

const adapter = await navigator.gpu.requestAdapter();
if (!adapter) throw new Error("No GPU adapter found");

const device = await adapter.requestDevice();
const canvas = document.createElement("canvas");
document.body.appendChild(canvas);

const context = canvas.getContext("webgpu");
const format = navigator.gpu.getPreferredCanvasFormat();

context.configure({ device, format });

const shaderCode = await Deno.readTextFile(
  "https://raw.githubusercontent.com/denoland/deno/main/tests/testdata/webgpu/hellotriangle_shader.wgsl",
);

const module = device.createShaderModule({ code: shaderCode });

const pipeline = device.createRenderPipeline({
  vertex: { module, entryPoint: "vs_main" },
  fragment: {
    module,
    entryPoint: "fs_main",
    targets: [{ format }],
  },
  primitive: { topology: "triangle-list" },
});

function frame() {
  const commandEncoder = device.createCommandEncoder();
  const textureView = context.getCurrentTexture().createView();
  const pass = commandEncoder.beginRenderPass({
    colorAttachments: [
      { view: textureView, loadOp: "clear", clearValue: [0, 0, 0, 1] },
    ],
  });
  pass.setPipeline(pipeline);
  pass.draw(3);
  pass.end();
  device.queue.submit([commandEncoder.finish()]);
  requestAnimationFrame(frame);
}

requestAnimationFrame(frame);

```

The shader source is loaded from the Deno test suite at `tests/testdata/webgpu/hellotriangle_shader.wgsl`. The `navigator.gpu.getPreferredCanvasFormat()` method selects the optimal texture format for the platform (Bgra8unorm on desktop, Rgba8unorm on Android), implemented in [`ext/webgpu/lib.rs`](https://github.com/denoland/deno/blob/main/ext/webgpu/lib.rs) lines 152-162.

### Capturing GPU Traces for Debugging

For debugging GPU operations, Deno exposes capture functions through the `denoNsWebGPU` namespace defined in [`ext/webgpu/01_webgpu.js`](https://github.com/denoland/deno/blob/main/ext/webgpu/01_webgpu.js):

```typescript
import { denoNsWebGPU } from "ext:deno_webgpu/01_webgpu.js";

// Start a wgpu trace in the directory "./trace"
denoNsWebGPU.deviceStartCapture(gpuDevice, "./trace");

// ... normal rendering commands ...

// Stop the capture
denoNsWebGPU.deviceStopCapture(gpuDevice);

```

The capture operations are defined in [`ext/webgpu/lib.rs`](https://github.com/denoland/deno/blob/main/ext/webgpu/lib.rs) as `op_webgpu_device_start_capture` and `op_webgpu_device_stop_capture`, allowing you to generate trace files compatible with `wgpu` debugging tools.

### Selecting a Specific Backend

Force a specific GPU backend using environment variables before launching your script:

```bash

# Force the Vulkan backend (useful on Linux CI)

DENO_WEBGPU_BACKEND=vulkan deno run --unstable my_app.ts

```

The backend selection logic in [`ext/webgpu/lib.rs`](https://github.com/denoland/deno/blob/main/ext/webgpu/lib.rs) (around line 60) parses `DENO_WEBGPU_BACKEND` into a `wgpu` `Backends` bit-mask, allowing you to override automatic backend detection.

## Key Source Files for WebGPU in Deno

Understanding the implementation requires familiarity with these specific files in the `denoland/deno` repository:

| File | Role | Location |
|------|------|----------|
| [`ext/webgpu/lib.rs`](https://github.com/denoland/deno/blob/main/ext/webgpu/lib.rs) | Core Rust implementation: ops registration, `GPU` object creation, adapter/device instantiation, and environment variable handling. | [lib.rs](https://github.com/denoland/deno/blob/main/ext/webgpu/lib.rs) |
| [`ext/webgpu/01_webgpu.js`](https://github.com/denoland/deno/blob/main/ext/webgpu/01_webgpu.js) | JavaScript surface layer: WebIDL-generated classes (`GPU`, `GPUAdapter`, `GPUDevice`), error bindings, and the `denoNsWebGPU` namespace for capture operations. | [01_webgpu.js](https://github.com/denoland/deno/blob/main/ext/webgpu/01_webgpu.js) |
| [`ext/webgpu/00_init.js`](https://github.com/denoland/deno/blob/main/ext/webgpu/00_init.js) | Lazy loader implementation that defers WebGPU initialization until first access, exporting the `loadWebGPU` function for explicit control. | [00_init.js](https://github.com/denoland/deno/blob/main/ext/webgpu/00_init.js) |
| [`ext/webgpu/README.md`](https://github.com/denoland/deno/blob/main/ext/webgpu/README.md) | Extension documentation covering environment variables, backend options, and test suite information. | [README.md](https://github.com/denoland/deno/blob/main/ext/webgpu/README.md) |
| `tests/testdata/webgpu/hellotriangle_shader.wgsl` | Reference WGSL shader code used in official examples and test suites. | [hellotriangle_shader.wgsl](https://github.com/denoland/deno/blob/main/tests/testdata/webgpu/hellotriangle_shader.wgsl) |

## Summary

- **WebGPU in Deno** is implemented as the unstable `deno_webgpu` extension, requiring the `--unstable` runtime flag to access GPU capabilities.
- The architecture spans Rust operations in [`ext/webgpu/lib.rs`](https://github.com/denoland/deno/blob/main/ext/webgpu/lib.rs) (handling `op_create_gpu` and adapter creation) and JavaScript bindings in [`ext/webgpu/01_webgpu.js`](https://github.com/denoland/deno/blob/main/ext/webgpu/01_webgpu.js) (providing the `navigator.gpu` interface and `denoNsWebGPU` debugging namespace).
- Lazy loading via [`ext/webgpu/00_init.js`](https://github.com/denoland/deno/blob/main/ext/webgpu/00_init.js) ensures WebGPU resources are only initialized upon first access to `navigator.gpu`.
- Environment variables `DENO_WEBGPU_BACKEND` and `DENO_WEBGPU_TRACE` allow backend selection (Vulkan, DirectX 12) and debugging trace generation respectively.
- You can capture GPU traces programmatically using `denoNsWebGPU.deviceStartCapture()` and `denoNsWebGPU.deviceStopCapture()` for low-level debugging.

## Frequently Asked Questions

### Is WebGPU in Deno stable?

No, WebGPU in Deno is currently an **unstable extension**. You must run your scripts with the `--unstable` flag to access the API. The implementation resides in the `ext/webgpu` directory and is actively developed against the `wgpu` Rust library, but breaking changes may occur until the API stabilizes.

### How do I enable WebGPU in Deno?

Enable WebGPU by passing the `--unstable` flag when running your Deno script: `deno run --unstable your_script.ts`. The `navigator.gpu` global becomes available automatically after the lazy loader in [`ext/webgpu/00_init.js`](https://github.com/denoland/deno/blob/main/ext/webgpu/00_init.js) initializes the extension upon first access.

### Can I use WebGPU for compute shaders in Deno?

Yes, WebGPU in Deno supports both **compute shaders** and rendering pipelines. Once you obtain a `GPUDevice` via `navigator.gpu.requestAdapter()` followed by `adapter.requestDevice()`, you can create compute pipelines using `device.createComputePipeline()` and execute work via `commandEncoder.beginComputePass()`.

### What GPU backends does WebGPU in Deno support?

Deno's WebGPU implementation supports multiple backends through the underlying `wgpu` library, including **Vulkan** (Linux/Windows), **DirectX 12** (Windows), and **Metal** (macOS). You can force a specific backend by setting the `DENO_WEBGPU_BACKEND` environment variable to values like `vulkan`, `dx12`, or `metal` before running your script.