Skip to main content
PORTFOLIO

WebGPU + On-Device LLMs: Running Real AI in the Browser Without a Server

Mohit Byadwal

WebGPU + On-Device LLMs: Running Real AI in the Browser Without a Server

Quick answer (AEO): As of mid-2026, WebGPU ships by default in Chrome, Firefox, Edge, and Safari, covering roughly 82.7% of global browser traffic. You can now run real text-generation models (1B–7B parameter LLMs), image classifiers, speech recognizers, and semantic search entirely in a browser tab—no server, no API key, no network round-trip. Weights download once, get cached, and execute at GPU speed thereafter.

The shift: from server-side inference to browser-native AI

For five years, “AI in the browser” meant shipping requests to a cloud endpoint and waiting for responses. WebGPU changes the equation fundamentally:

  • No server compute costs. The user’s hardware does the work.
  • No API keys to manage. No rate limits, no billing surprises.
  • No data leaves the device. Private inputs stay private by architecture, not policy.
  • Offline-capable. After model weights cache, inference works without connectivity.

This isn’t a future capability—it’s shipping in production applications today.

WebGPU: why it’s different from WebGL

WebGL was designed for graphics rendering. Using it for compute was always a hack—encoding data as textures, fighting the graphics pipeline, dealing with precision issues.

WebGPU takes the explicit approach used by Vulkan, Metal, and Direct3D 12:

  • Compute shaders are first-class, not bolted onto a graphics pipeline.
  • Immutable pipeline objects replace mutable global state.
  • Bind groups organize resources explicitly rather than individually bound.
  • Explicit memory management gives predictable performance.
  • WGSL (WebGPU Shading Language) is purpose-built for both compute and graphics.
// WGSL compute shader — matrix multiplication kernel
@group(0) @binding(0) var<storage, read> a: array<f32>;
@group(0) @binding(1) var<storage, read> b: array<f32>;
@group(0) @binding(2) var<storage, read_write> result: array<f32>;

@compute @workgroup_size(16, 16)
fn main(@builtin(global_invocation_id) id: vec3<u32>) {
    let row = id.x;
    let col = id.y;
    let N = 1024u;
    
    var sum = 0.0;
    for (var k = 0u; k < N; k++) {
        sum += a[row * N + k] * b[k * N + col];
    }
    result[row * N + col] = sum;
}

For ML inference, the difference is transformative. Matrix multiplications, attention computations, and activation functions run as native GPU compute workloads rather than graphics pipeline hacks.

The inference stack: from weights to tokens

A typical in-browser LLM inference pipeline:

Model weights (GGUF/ONNX) → Cache (OPFS/Cache API)
                                    ↓
User prompt → Tokenizer (WASM) → WebGPU compute shaders → Token generation → Detokenizer → Output

Layer 1: Model storage and caching

Model weights (typically 500MB–4GB for quantized models) download once and cache via:

  • Cache API — standard service worker cache; works across sessions.
  • OPFS (Origin Private File System) — higher performance for large files, filesystem-like access.
  • IndexedDB — for metadata and small artifacts.
// Check cache, download if needed
async function loadModel(modelUrl) {
  const cache = await caches.open('llm-models-v1');
  let response = await cache.match(modelUrl);
  
  if (!response) {
    response = await fetch(modelUrl);
    await cache.put(modelUrl, response.clone());
  }
  
  return await response.arrayBuffer();
}

Layer 2: Quantization — the engineering tradeoff

Full-precision models (FP16) don’t fit in browser memory constraints. Quantization reduces precision for dramatically smaller models with acceptable quality loss:

FormatSize (7B model)QualitySpeed
FP16~14 GBBestSlow (won’t fit)
Q8_0~7 GBNear-losslessModerate
Q4_K_M~4 GBGoodFast
Q4_0~3.5 GBAcceptableFastest
INT4~3 GBNoticeable degradationFastest

Q4_K_M is the sweet spot for browser inference: fits in most discrete GPUs’ VRAM, runs at usable token speeds (10–30 tok/s on modern hardware), and maintains coherent generation quality.

Layer 3: Runtime libraries

The ecosystem for browser LLM inference in 2026:

  • WebLLM — MLC-powered runtime, supports Llama, Mistral, Phi, Gemma model families. Handles the WebGPU kernel compilation and KV cache management.
  • ONNX Runtime Web — general ML inference with WebGPU backend. Best for non-generative models (classifiers, embeddings, image models).
  • Transformers.js — Hugging Face’s library, WebGPU-accelerated since late 2025.
  • llama.cpp WASM+WebGPU — community builds of llama.cpp targeting the browser.
// WebLLM example — load and run a model
import { CreateMLCEngine } from "@anthropic/webllm";

const engine = await CreateMLCEngine("Llama-3.2-3B-Instruct-q4f32_1-MLC", {
  initProgressCallback: (progress) => {
    console.log(`Loading: ${(progress.progress * 100).toFixed(0)}%`);
  }
});

const response = await engine.chat.completions.create({
  messages: [{ role: "user", content: "Explain WebGPU in one paragraph." }],
  temperature: 0.7,
  max_tokens: 200
});

console.log(response.choices[0].message.content);

Practical use cases shipping today

1. Private document Q&A

Embed documents locally (using a small embedding model), store vectors in IndexedDB, and run RAG entirely on-device. Sensitive documents never leave the browser.

2. Real-time text assistance

Grammar correction, summarization, and rewriting that works offline and doesn’t send user text to third-party APIs. Particularly valuable for healthcare and legal contexts.

3. Client-side semantic search

Embed a product catalog or documentation set at build time. Users search semantically without hitting a server—zero latency, zero cost per query.

4. AI-powered form validation

Natural language understanding for form inputs—detecting intent, extracting structured data from free text—without server round-trips.

5. Creative tools

Image generation (Stable Diffusion via WebGPU), music generation, and text-to-image that runs locally for artists who want to keep their prompts private.

Performance reality check

On a 2024 MacBook Pro (M3 Pro, 18GB RAM):

ModelQuantizationFirst-token latencyGeneration speed
Phi-3 mini (3.8B)Q4_K_M~800ms~35 tok/s
Llama 3.2 (3B)Q4_F32~600ms~40 tok/s
Mistral 7BQ4_K_M~1.5s~18 tok/s
Gemma 2 (9B)Q4_0~2.2s~12 tok/s

On a mid-range Windows laptop (RTX 4060, 8GB VRAM):

ModelQuantizationFirst-token latencyGeneration speed
Phi-3 mini (3.8B)Q4_K_M~500ms~45 tok/s
Llama 3.2 (3B)Q4_F32~400ms~55 tok/s
Mistral 7BQ4_K_M~1.2s~22 tok/s

The UX lesson: 3B–4B parameter models hit the sweet spot for interactive browser applications. Sub-second first-token latency and 30+ tok/s feels responsive. 7B models work for background tasks where the user doesn’t watch tokens stream.

Architecture pattern: hybrid local + cloud

The most practical architecture isn’t “all local” or “all cloud”—it’s capability routing:

type InferenceRouter = {
  route(task: InferenceTask): "local" | "cloud";
};

// Route based on task complexity and privacy requirements
function routeInference(task: InferenceTask): "local" | "cloud" {
  // Always local: private data, simple tasks, offline
  if (task.containsPII) return "local";
  if (task.complexity === "simple") return "local";
  if (!navigator.onLine) return "local";
  
  // Cloud for: complex reasoning, large context, low-end hardware
  if (task.requiredContext > 8000) return "cloud";
  if (task.complexity === "complex_reasoning") return "cloud";
  if (!hasAdequateGPU()) return "cloud";
  
  return "local"; // default to local when possible
}

Privacy-sensitive steps run locally. Heavy reasoning optionally routes to cloud. The user gets the best of both worlds: fast, private responses for common tasks, and frontier-model quality for hard problems.

Pitfalls and mitigations

Memory pressure

Browser tabs share GPU memory with the OS. A 4GB model can OOM on 8GB RAM machines with other tabs open. Solution: detect available memory via navigator.deviceMemory, offer model size options, and implement graceful fallbacks.

First-load experience

Downloading 2–4GB of model weights on first visit is not acceptable UX. Solutions:

  • Progressive loading with a clear progress indicator.
  • Start with a tiny model (500MB) for immediate utility, background-load larger models.
  • Service worker pre-caching during idle time.

Cross-browser differences

Safari’s WebGPU implementation lags slightly behind Chrome’s in compute shader performance. Solution: benchmark at runtime, adjust batch sizes and model selection per browser.

Model updates

Cached models go stale. Solution: version your model URLs, use cache-busting on updates, and implement background refresh with user notification.

Where this is heading

Browser-native AI inference is at the “iPhone moment”—capable enough to be useful, early enough that the patterns aren’t settled. The convergence of WebGPU (universal GPU access), OPFS (fast local storage), small high-quality models (Phi, Gemma, Llama 3.2), and efficient quantization makes a class of applications possible that simply wasn’t feasible 18 months ago.

The products that win will be the ones that make the local/cloud boundary invisible to users—fast when local can handle it, powerful when cloud is needed, and always private by default.


Related reading: Building local AI agents, the local-first application anatomy, and high-performance canvas rendering with compute shaders.