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

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.

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:

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 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 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 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:


# 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 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:

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:

// 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 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:

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 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:


# 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 (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 Core Rust implementation: ops registration, GPU object creation, adapter/device instantiation, and environment variable handling. lib.rs
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
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
ext/webgpu/README.md Extension documentation covering environment variables, backend options, and test suite information. README.md
tests/testdata/webgpu/hellotriangle_shader.wgsl Reference WGSL shader code used in official examples and test suites. 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 (handling op_create_gpu and adapter creation) and JavaScript bindings in ext/webgpu/01_webgpu.js (providing the navigator.gpu interface and denoNsWebGPU debugging namespace).
  • Lazy loading via 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 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.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →