WebGPU: Real GPU Power Comes to the Browser
WebGPU is far more than a WebGL replacement. It exposes compute shaders, maps to modern GPU APIs, and enables in-browser ML inference.
Running machine learning models directly in the browser — with no server round-trip, no API key, no cloud cost — was effectively impossible at any reasonable scale until very recently. WebGPU changes that. It is not simply a shinier coat of paint on WebGL; it is a ground-up redesign of how web applications talk to the GPU, and the implications extend well beyond 3D graphics.
What WebGPU actually is
WebGPU is a low-level JavaScript API that gives web applications direct access to the GPU for two distinct purposes: graphics rendering and general-purpose compute. That second capability is what sets it apart. WebGL, the API it supersedes, was designed around OpenGL ES and optimized for rendering — using it for non-graphics computation required awkward workarounds that were slow and brittle. WebGPU has first-class compute shaders, making it suitable for the same workloads that developers currently run on CUDA or Metal compute kernels in native apps.
Under the hood, WebGPU is a thin abstraction layer that maps onto the modern native graphics APIs: Vulkan on Linux and Android, Metal on macOS and iOS, and Direct3D 12 on Windows. This is meaningful because it means the performance characteristics and mental model are closer to what GPU engineers already understand, and the browser can translate WebGPU calls to native driver commands with minimal overhead.
WGSL: a new shading language
WebGPU introduces its own shader language called WGSL (WebGPU Shading Language). It replaces GLSL and SPIR-V as the primary way to write code that runs on the GPU. WGSL is statically typed, designed to be safe to compile at runtime, and looks superficially familiar to anyone who has written Rust or Swift.
A minimal compute shader in WGSL looks like this:
@group(0) @binding(0) var<storage, read_write> data: array<f32>;
@compute @workgroup_size(64)
fn main(@builtin(global_invocation_id) id: vec3<u32>) {
data[id.x] = data[id.x] * 2.0;
}
And on the JavaScript side, getting access to the GPU starts with requesting an adapter and device:
const adapter = await navigator.gpu.requestAdapter();
const device = await adapter.requestDevice();
From there you create pipelines, bind buffers, dispatch workgroups, and read results back — a much more explicit model than WebGL, but one that rewards the explicitness with predictable performance.
Why it beats WebGL
The differences between WebGL and WebGPU are not cosmetic. A few that matter in practice:
- Explicit pipelines: WebGL’s state machine model means driver behavior can be unpredictable across vendors. WebGPU uses explicit pipeline state objects, so what you compile is what you get.
- Compute shaders: First-class
@computeshaders let you run arbitrary parallel workloads — not just vertex/fragment passes. - Better multithreading: WebGPU is designed to work with Web Workers, so GPU work can be offloaded from the main thread without awkward message-passing gymnastics.
- Modern driver alignment: Because WebGPU targets Vulkan, Metal, and D3D12, it sidesteps the years of legacy baggage in OpenGL driver implementations.
The killer use cases
In-browser machine learning is the headline story. Frameworks like ONNX Runtime Web and TensorFlow.js already ship WebGPU backends. This means you can run inference on a vision model, a text classifier, or increasingly a small language model entirely on the client — no data leaves the device, latency drops to near-zero, and the cost is zero. Pair this with running LLMs locally with Ollama and the picture of local-first AI becomes significantly clearer.
Data visualization and simulation are natural fits. WebGPU can process and render large point clouds, particle systems, or fluid simulations that would choke WebGL. Scientific dashboards and geospatial tools are already experimenting with it.
Games get the biggest raw graphics uplift: instanced rendering, better shadow techniques, deferred pipelines — all the techniques that modern game engines take for granted.
For a broader view of how browser capabilities are expanding, the WebAssembly and its effect on the web platform is worth reading alongside this — the two technologies are increasingly used together, with Wasm handling logic and WebGPU handling compute.
Where things stand today
WebGPU shipped in Chromium-based browsers and is available in Chrome and Edge on Windows, macOS, and Linux. Firefox and Safari have been working through their implementations, with support rolling out progressively; status is best checked against the browser release notes rather than assumed from any snapshot. The API surface is stable — it graduated from origin trial to stable in Chrome some time ago — so libraries and tooling are converging on it with confidence.
If you want to experiment today, the browser DevTools and navigator.gpu availability check are your starting points. The WebGPU samples repository maintained by the spec authors is also a practical reference.
The takeaway
WebGPU is a genuine platform shift, not a graphics API update. The combination of explicit pipelines, compute shaders, and alignment with modern GPU drivers means the browser is now a credible environment for workloads that previously demanded native code. The near-term impact most developers will feel is through ML libraries gaining WebGPU backends — faster inference, client-side privacy, no server required. The longer-term impact is harder to bound.
Tagged
Keep reading
Takina · · 4 min read What Is the Beacon API? navigator.sendBeacon()
The Beacon API lets a page send one last async request as it unloads, without blocking navigation or racing the browser's page teardown.
Takina · · 3 min read What Is Fetch Priority? The fetchpriority Attribute
fetchpriority lets you tell the browser which resources matter most, overriding its default heuristics to load critical assets sooner.
Takina · · 4 min read requestIdleCallback Explained
requestIdleCallback runs low-priority JavaScript when the browser is idle, without blocking rendering, input, or the main thread.