◉GEMINI LABJP
●ARGON — gemini-4-argon is generally available as of 10/13, aimed at complex coding, agents, math and science●DEEP RES — deep-research-pro-preview-12-2025 shuts down 10/23, 6 days left. Move to deep-research-preview-04-2026●NANO — gemini-nano-banana-2.1 is GA (10/06). gemini-3.1-flash-image is deprecated with no shutdown date yet●MCP — One write-up cut an 85,000-token tool result to 310 tokens by wrapping it in an ADK FunctionTool●FLASH — gemini-3.7-flash and 3.5-flash now route automatically to newer Flash models (10/08)●NEW — Stop Re-Reading Every Crash Report: Gre…●ARGON — gemini-4-argon is generally available as of 10/13, aimed at complex coding, agents, math and science●DEEP RES — deep-research-pro-preview-12-2025 shuts down 10/23, 6 days left. Move to deep-research-preview-04-2026●NANO — gemini-nano-banana-2.1 is GA (10/06). gemini-3.1-flash-image is deprecated with no shutdown date yet●MCP — One write-up cut an 85,000-token tool result to 310 tokens by wrapping it in an ADK FunctionTool●FLASH — gemini-3.7-flash and 3.5-flash now route automatically to newer Flash models (10/08)●NEW — Stop Re-Reading Every Crash Report: Gre…
Articles/Dev Tools
⟐ Dev Tools/2026-04-27Advanced

Building Stateful AI Agents with Gemini API and Cloudflare Durable Objects — A

A complete production guide to building a stateful AI agent that remembers conversation history, using Cloudflare Durable Objects, WebSocket Hibernation, and the Gemini API streaming endpoint.

gemini-api286cloudflare4durable-objectswebsocket4agent10

✦ Premium Article

"Can the AI remember what I told it yesterday?" is a request that comes up in almost every chat app I have shipped as a solo developer. The Gemini API itself does not retain conversation state between calls, so the server has to keep that history. Over the past year I have tried KV-backed, D1-backed, and Postgres-backed approaches, and the combination of Cloudflare Durable Objects with the Gemini API has consistently come out on top in terms of cost and operational simplicity.

This article walks through the production design I have settled on. The structure is deliberately built around the mistakes I made — the things I had to fix at 2am, the architectures I tore out and rebuilt — so you can short-circuit those steps.

Why Durable Objects: the Workers state problem

Cloudflare Workers are a wonderful edge runtime, but they are stateless. Every request might land on a different worker instance, so any in-memory data disappears between calls. That is fine for stateless API gateways, but a chat agent is not stateless.

You could keep the history in KV or in D1 (Cloudflare's distributed SQLite). The trouble is concurrency. When two requests for the same conversation arrive nearly simultaneously, both read the current history, both append to it, and both write it back. Whichever finishes second silently overwrites the first — the classic lost update. In a KV-backed chat I ran in 2025, this manifested as user complaints like "wait, my last message just disappeared." It took me an embarrassing amount of time to realize the issue was structural, not a UI bug.

Durable Objects solve this by guaranteeing that for any given key — say userId:sessionId — there is exactly one live instance in the world. Every request for that key is routed to the same instance, and the instance can hold both in-memory state and SQLite-backed durable state, in a strictly serialized order. For a conversational agent, that single-writer property is exactly what you want.

The pricing also lands in a sensible place for indie developers. The Workers Paid plan at $5/month includes Durable Objects with generous request and compute allowances. For a hundred-user-scale app, you are looking at a few extra dollars a month rather than the $25+ floor of a managed Postgres tier.

What you will build

Here is the system the rest of the article walks through:

  • A browser chat UI that connects via WebSocket
  • One Durable Object per session, persisting history in built-in SQLite
  • User messages routed to Gemini 2.5 Pro, with replies streamed back over the WebSocket
  • Automatic summarization once the history exceeds a threshold, so the context window does not blow up
  • Hibernation enabled, so idle sessions cost nothing in compute

The whole thing fits in three files: wrangler.toml, src/worker.ts, and src/agent.ts. Seeing the small surface area first helps each subsequent section feel less abstract.

✦

Thank you for reading this far.

Continue Reading

What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.

WHAT YOU'LL LEARN
✦Get a working stateful AI chat backend that solo developers can ship to production this week, not the kind of toy you abandon after a weekend.
✦Avoid the WebSocket Hibernation, SQLite transaction, and concurrency pitfalls I hit running a chat agent in production for a year.
✦Run a 24/7 conversational AI service for a few dollars a month rather than the $50+ a Postgres-backed setup costs at the same scale.
Secure payment via Stripe · Cancel anytime
✦

Unlock This Article

Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.

or
Unlock all articles with Membership →
Share

Thank You for Reading

Gemini Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • ✦Copy-paste ready implementation code
  • ✦New advanced guides published daily
  • ✦$5/mo or $10 for lifetime access
View Membership →

Related Articles

⟐ Dev Tools2026-08-21
Why My Length Limit Only Failed on the English Notifications, and the Width-Based Fit That Replaced It
I had Gemini write push notifications in Japanese and English, and only the English ones came out truncated on real devices. The culprit was measuring length in characters. Here are the measured widths and the post-generation fitting code that fixed it.
⟐ Dev Tools2026-08-10
Finding the questions your help docs never answer, by asking Gemini to write the quiz
When support keeps asking something your help page already covers, generate questions from that page and check whether the page alone can answer them. A two-pass audit pipeline with call design and cost math.
⟐ Dev Tools2026-04-18
Building Cross-Platform AI Desktop Apps with Gemini API and Tauri 2.0
A practical guide to building macOS, Windows, and Linux desktop AI apps using Tauri 2.0 and Gemini API. Learn secure API key management with a Rust backend, real-time streaming via Tauri's event system, and native OS integration with working production code.