Hybrid Web AI Architecture: Routing Between Browser Gemini Nano, Firebase AI Logic, and Edge Workers

how this post connects together.
Follow AJ from first principles to production-ready architecture.
The biggest mistake web engineering teams make when adopting client-side AI is treating it as an all-or-nothing binary choice: either 100% of inference runs in the browser or 100% runs in the cloud. In real-world production, visitor hardware spans everything from an M4 Max MacBook Pro with Chrome's on-device Gemini Nano cached in VRAM to a budget mobile browser on a cellular connection. The solution is Hybrid Browser-to-Edge AI Routing.
By pairing Chrome's local window.LanguageModel API with Firebase AI Logic (or a Cloudflare Worker edge gateway calling Gemini 2.5 Flash), you can build a unified TypeScript router that offloads 70%+ of routine summarization, classification, and UI drafting tasks to the user's device at $0 cost while seamlessly routing complex reasoning or unsupported browsers to the edge.
The Mental Model: Adaptive Capability & Complexity Routing
Our hybrid router evaluates three deterministic gates before dispatching a prompt: (1) Hardware Availability (is Chrome's LanguageModel.availability() === 'available' immediately ready without blocking on a multi-hundred-megabyte download?), (2) Context Budget (does the prompt fit comfortably inside Gemini Nano's local token quota?), and (3) Task Complexity (does the request require multi-hop tool calling or massive 100K-token context?).

Comparing Local-Only, Cloud-Only, and Hybrid Browser-to-Edge Architectures
| Architectural Metric | Local-Only (Browser AI) | Cloud-Only (Server LLM API) | Hybrid Browser-to-Edge Router (Recommended) |
|---|---|---|---|
| Browser Coverage | Desktop Chrome / Edge with GPU/NPU | 100% of browsers (requires network) | 100% of browsers (local fast-lane + cloud fallback) |
| P50 Time-to-First-Token (TTFT) | 15ms to 45ms (0ms network RTT) | 280ms to 650ms | 25ms on capable desktops / 280ms on mobile fallback |
| Unit Economics (50K MAU) | $0.00 / month | $450 to $1,800 / month | 70% to 80% cost reduction via local offload |
| Offline Resilience | Full offline execution | Fails when offline | Graceful offline mode for local tasks + cloud sync when online |
Production Implementation: The Unified Hybrid Web AI Router
Here is the complete TypeScript router pattern that pairs Chrome's native window.LanguageModel with Firebase AI Logic's hybrid on-device/cloud model abstraction and an Astro Cloudflare Worker fallback:
// src/lib/ai/hybrid-web-ai-router.ts
export type InferenceRoute = "local-gemini-nano" | "edge-gemini-flash";
export interface HybridPromptRequest {
prompt: string;
systemPrompt?: string;
complexity?: "fast-local-preferred" | "reasoning-cloud-required";
maxLocalTokens?: number;
signal?: AbortSignal;
}
export interface HybridPromptResponse {
text: string;
route: InferenceRoute;
latencyMs: number;
estimatedCloudCostSavedUsd: number;
}
export async function runHybridWebAiPrompt(
req: HybridPromptRequest
): Promise<HybridPromptResponse> {
const start = performance.now();
const maxLocalTokens = req.maxLocalTokens ?? 2048;
// 1. Attempt Fast Lane: Local Chrome Built-in AI (Gemini Nano)
if (req.complexity !== "reasoning-cloud-required") {
const lm = (globalThis as Record<string, any>).LanguageModel;
if (lm && typeof lm.availability === "function") {
try {
const status = await lm.availability();
// Only route locally if weights are already warm/available on disk
if (status === "available") {
const session = await lm.create({
systemPrompt:
req.systemPrompt ??
"You are a technical assistant on CodingCat.dev. Be concise and accurate.",
signal: req.signal,
});
try {
const usage = await session.measureInputUsage(req.prompt);
if (usage <= maxLocalTokens && usage < session.inputQuota - session.inputUsage) {
const text = await session.prompt(req.prompt, { signal: req.signal });
return {
text,
route: "local-gemini-nano",
latencyMs: Number((performance.now() - start).toFixed(1)),
estimatedCloudCostSavedUsd: 0.00042,
};
}
} finally {
session.destroy();
}
}
} catch (localErr) {
console.warn("[HybridWebAI] Local Gemini Nano failed, falling back to edge:", localErr);
}
}
}
// 2. Fallback Lane: Cloudflare Worker / Firebase AI Logic Edge Endpoint (Gemini 2.5 Flash)
const edgeRes = await fetch("/api/ai/hybrid-fallback", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
prompt: req.prompt,
systemPrompt: req.systemPrompt,
}),
signal: req.signal,
});
if (!edgeRes.ok) {
throw new Error(`Hybrid Edge AI fallback failed with HTTP ${edgeRes.status}`);
}
const data = (await edgeRes.json()) as { text: string };
return {
text: data.text,
route: "edge-gemini-flash",
latencyMs: Number((performance.now() - start).toFixed(1)),
estimatedCloudCostSavedUsd: 0,
};
}Warming the Local Model in the Background Without Blocking UX
Notice how our router above only takes the local fast lane when status === 'available'. What if the user's browser returns 'downloadable'? Instead of making the user wait 30 seconds on their first prompt, fulfill their immediate request via the edge-gemini-flash route while triggering LanguageModel.create() asynchronously in the background. Once the download completes, every subsequent prompt in their session automatically upgrades to the 0ms local lane.
Try the Live Browser AI & WebMCP Playground
You can test every pattern from this article live right now in our interactive Web AI & WebMCP Playground on CodingCat.dev, or inspect our production discovery manifests on the Developers & Agent APIs page. If you are organizing a developer conference or engineering summit, check out my Web AI talk abstracts on alexpatterson.dev and explore more hands-on Courses, Podcasts, and Blog Posts right here on CodingCat.dev.
