June 10, 2025Ask AI
At a recent event in London, I was excited to learn how RedwoodSDK makes it easy to run React Server Components (RSC) on Cloudflare.
I decided to learn more about this by building multi-user AI chat - 4 times.
- RSC Chat - sync via RedwoodSDK realtime websockets
- Agent Chat - sync via Cloudflare Agents websockets
- Agent SDK Chat - uses AIChatAgent with the useAgentChat hook
- TinyBase Chat - sync via TinyBase websockets
Deployed at https://agents-chat.jldec.workers.dev/
The primary challenge with this use-case is live-streaming AI responses back to multiple connected clients at the same time. Details in the code on GitHub.
I'd ❤️ to see if there are ways to combine the best of all the approaches above.
And I believe multi-user AI chat could be the beginning of something much bigger.
- Agents and humans organize into specialized groups.
- Agents with tools do much of the work.
- Persisted conversations become the new basis for organizational memory.
Bright futures ahead 🚀
{ "path": "/blog/multi-user-ai-chat-with-redwoodsdk-rsc-and-cloudflare-agents", "attrs": { "title": "Multi-user AI chat with RedwoodSDK RSC and Cloudflare agents", "date": "2025-06-10", "splash": { "image": "/images/flowzer.webp" }, "layout": "BlogPostLayout" }, "md": "# Multi-user AI chat with RedwoodSDK RSC and Cloudflare agents\n\nAt a recent event in London, I was excited to learn how [RedwoodSDK](https://rwsdk.com/) makes it easy to run React Server Components (RSC) on Cloudflare.\n\nI decided to learn more about this by building multi-user AI chat - 4 times.\n\n> 1. [RSC Chat](https://agents-chat.jldec.workers.dev/chat-rsc) - sync via [RedwoodSDK realtime websockets](https://docs.rwsdk.com/core/realtime/)\n> 2. [Agent Chat](https://agents-chat.jldec.workers.dev/chat-agent) - sync via [Cloudflare Agents websockets](https://developers.cloudflare.com/agents/api-reference/websockets/)\n> 3. [Agent SDK Chat](https://agents-chat.jldec.workers.dev/chat-agent-sdk) - uses [AIChatAgent](https://developers.cloudflare.com/agents/api-reference/agents-api/#aichatagent) with the [useAgentChat](https://developers.cloudflare.com/agents/api-reference/agents-api/#chat-agent-react-api) hook\n> 3. [TinyBase Chat](https://agents-chat.jldec.workers.dev/chat-tinybase) - sync via [TinyBase websockets](https://tinybase.org/)\n\nDeployed at https://agents-chat.jldec.workers.dev/\n\nThe primary challenge with this use-case is live-streaming AI responses back to multiple connected clients at the same time. Details in the code on [GitHub](https://github.com/jldec/agents-chat).\n\n## First impressions\n- RedwoodSDK (RSCs on Cloudflare workers) is very interesting. The upcoming addition of client-side routing (SPA mode) together with Cloudflare cache integration for SSR, would make this stack hard to beat.\n- All four implementations rely on Cloudflare [durable objects](https://developers.cloudflare.com/durable-objects/#what-are-durable-objects) with websockets. This is great for runtime performance and makes deployment easy. There are no containers to build or servers to manage.\n- React is great for a use case like this where updates are coming from both the server and the client. All four implementations use the same [MessageList](https://github.com/jldec/agents-chat/blob/main/src/app/shared/MessageList.tsx) component.\n\n#### RedwoodSK realtime RSC\n- Server components are a [succinct](https://github.com/jldec/agents-chat/blob/main/src/app/chat-rsc/ChatRSC.tsx) way to pre-populate JSX with data and then keep clients up to date.\n- It's nice to be able to use async data loading inline on the server. Rendering with data from remote storage during streaming can be slower unless data is memoized.\n- The scope of the RSC update payload sent to clients may become a problem during streaming, e.g. for pages with a lot of data. Discussion about this in the [rwsdk discord](https://discord.com/channels/679514959968993311/1374715298636238968/1376288266789064734).\n- Server functions are convenient, but should be used with care since they generate HTTP APIs which is where auth/authz is commonly required. See [this take](https://www.youtube.com/watch?v=yD-KK4hiULU) from Jack Herrington for more.\n\n#### Cloudflare Agents websockets\n- Using Cloudflare Agents websockets means that we have [full control](https://github.com/jldec/agents-chat/blob/main/src/app/chat-agent/WebsocketAgent.ts) over the payloads. This allows for nice optimizations e.g. to send partial data during streaming.\n- Rendering chat history on the client via fetch or via websocket makes the initial UX a little janky. (TODO: investigate pre-rendering)\n- Agents can combine both the chat storage and the websocket in one durable object. (TODO)\n\n#### Cloudflare Agents SDK with AIChatAgent\n- [AIChatAgent](https://developers.cloudflare.com/agents/api-reference/agents-api/#aichatagent) handles multi-user real-time message sync over websockets. This simplifies the implementation. (_still investigating [in #23](https://github.com/jldec/agents-chat/issues/23) why not all clients see the streaming_)\n- The SDK abstracts tool calling and supports different LLMs with Vercel's [AI SDK](https://ai-sdk.dev/docs/introduction).\n- [useAgentChat](https://developers.cloudflare.com/agents/api-reference/agents-api/#chat-agent-react-api) manages chat interactions with react.\n- With React Server Components (RSC), this component needs to be wrapped to prevent server-side rendering since the hook makes assumptions about running in a browser environment. More details in [this PR](https://github.com/jldec/agents-chat/pull/20).\n\n#### TinyBase sync\n- Synchronization is happening between memory and persistence on every node, and between nodes.\n- This improves the UX once data is persisted on the client and makes it easy to use React hooks listening for database updates.\n- The APIs for [persistence and synchronization](https://github.com/jldec/agents-chat/blob/main/src/app/chat-tinybase/store.ts#L14-L38) feel like they could be consolidated.\n- Since store operations run on the client we have to be extra careful with validation e.g. to deal with clients being compromised.\n- Localstorage persistence has an [issue](https://github.com/jldec/agents-chat/issues/13) with multiple tabs.\n\n## What's next?\n\nI'd ❤️ to see if there are ways to combine the best of all the approaches above.\n\nAnd I believe multi-user AI chat could be the beginning of something much bigger.\n\n> - Agents and humans organize into specialized groups.\n> - Agents with tools do much of the work.\n> - Persisted conversations become the new basis for organizational memory.\n\nBright futures ahead 🚀", "html": "<h1>Multi-user AI chat with RedwoodSDK RSC and Cloudflare agents</h1>\n<p>At a recent event in London, I was excited to learn how <a href=\"https://rwsdk.com/\">RedwoodSDK</a> makes it easy to run React Server Components (RSC) on Cloudflare.</p>\n<p>I decided to learn more about this by building multi-user AI chat - 4 times.</p>\n<blockquote>\n<ol>\n<li><a href=\"https://agents-chat.jldec.workers.dev/chat-rsc\">RSC Chat</a> - sync via <a href=\"https://docs.rwsdk.com/core/realtime/\">RedwoodSDK realtime websockets</a></li>\n<li><a href=\"https://agents-chat.jldec.workers.dev/chat-agent\">Agent Chat</a> - sync via <a href=\"https://developers.cloudflare.com/agents/api-reference/websockets/\">Cloudflare Agents websockets</a></li>\n<li><a href=\"https://agents-chat.jldec.workers.dev/chat-agent-sdk\">Agent SDK Chat</a> - uses <a href=\"https://developers.cloudflare.com/agents/api-reference/agents-api/#aichatagent\">AIChatAgent</a> with the <a href=\"https://developers.cloudflare.com/agents/api-reference/agents-api/#chat-agent-react-api\">useAgentChat</a> hook</li>\n<li><a href=\"https://agents-chat.jldec.workers.dev/chat-tinybase\">TinyBase Chat</a> - sync via <a href=\"https://tinybase.org/\">TinyBase websockets</a></li>\n</ol>\n</blockquote>\n<p>Deployed at <a href=\"https://agents-chat.jldec.workers.dev/\">https://agents-chat.jldec.workers.dev/</a></p>\n<p>The primary challenge with this use-case is live-streaming AI responses back to multiple connected clients at the same time. Details in the code on <a href=\"https://github.com/jldec/agents-chat\">GitHub</a>.</p>\n<h2>First impressions</h2>\n<ul>\n<li>RedwoodSDK (RSCs on Cloudflare workers) is very interesting. The upcoming addition of client-side routing (SPA mode) together with Cloudflare cache integration for SSR, would make this stack hard to beat.</li>\n<li>All four implementations rely on Cloudflare <a href=\"https://developers.cloudflare.com/durable-objects/#what-are-durable-objects\">durable objects</a> with websockets. This is great for runtime performance and makes deployment easy. There are no containers to build or servers to manage.</li>\n<li>React is great for a use case like this where updates are coming from both the server and the client. All four implementations use the same <a href=\"https://github.com/jldec/agents-chat/blob/main/src/app/shared/MessageList.tsx\">MessageList</a> component.</li>\n</ul>\n<h4>RedwoodSK realtime RSC</h4>\n<ul>\n<li>Server components are a <a href=\"https://github.com/jldec/agents-chat/blob/main/src/app/chat-rsc/ChatRSC.tsx\">succinct</a> way to pre-populate JSX with data and then keep clients up to date.</li>\n<li>It's nice to be able to use async data loading inline on the server. Rendering with data from remote storage during streaming can be slower unless data is memoized.</li>\n<li>The scope of the RSC update payload sent to clients may become a problem during streaming, e.g. for pages with a lot of data. Discussion about this in the <a href=\"https://discord.com/channels/679514959968993311/1374715298636238968/1376288266789064734\">rwsdk discord</a>.</li>\n<li>Server functions are convenient, but should be used with care since they generate HTTP APIs which is where auth/authz is commonly required. See <a href=\"https://www.youtube.com/watch?v=yD-KK4hiULU\">this take</a> from Jack Herrington for more.</li>\n</ul>\n<h4>Cloudflare Agents websockets</h4>\n<ul>\n<li>Using Cloudflare Agents websockets means that we have <a href=\"https://github.com/jldec/agents-chat/blob/main/src/app/chat-agent/WebsocketAgent.ts\">full control</a> over the payloads. This allows for nice optimizations e.g. to send partial data during streaming.</li>\n<li>Rendering chat history on the client via fetch or via websocket makes the initial UX a little janky. (TODO: investigate pre-rendering)</li>\n<li>Agents can combine both the chat storage and the websocket in one durable object. (TODO)</li>\n</ul>\n<h4>Cloudflare Agents SDK with AIChatAgent</h4>\n<ul>\n<li><a href=\"https://developers.cloudflare.com/agents/api-reference/agents-api/#aichatagent\">AIChatAgent</a> handles multi-user real-time message sync over websockets. This simplifies the implementation. (<em>still investigating <a href=\"https://github.com/jldec/agents-chat/issues/23\">in #23</a> why not all clients see the streaming</em>)</li>\n<li>The SDK abstracts tool calling and supports different LLMs with Vercel's <a href=\"https://ai-sdk.dev/docs/introduction\">AI SDK</a>.</li>\n<li><a href=\"https://developers.cloudflare.com/agents/api-reference/agents-api/#chat-agent-react-api\">useAgentChat</a> manages chat interactions with react.</li>\n<li>With React Server Components (RSC), this component needs to be wrapped to prevent server-side rendering since the hook makes assumptions about running in a browser environment. More details in <a href=\"https://github.com/jldec/agents-chat/pull/20\">this PR</a>.</li>\n</ul>\n<h4>TinyBase sync</h4>\n<ul>\n<li>Synchronization is happening between memory and persistence on every node, and between nodes.</li>\n<li>This improves the UX once data is persisted on the client and makes it easy to use React hooks listening for database updates.</li>\n<li>The APIs for <a href=\"https://github.com/jldec/agents-chat/blob/main/src/app/chat-tinybase/store.ts#L14-L38\">persistence and synchronization</a> feel like they could be consolidated.</li>\n<li>Since store operations run on the client we have to be extra careful with validation e.g. to deal with clients being compromised.</li>\n<li>Localstorage persistence has an <a href=\"https://github.com/jldec/agents-chat/issues/13\">issue</a> with multiple tabs.</li>\n</ul>\n<h2>What's next?</h2>\n<p>I'd ❤️ to see if there are ways to combine the best of all the approaches above.</p>\n<p>And I believe multi-user AI chat could be the beginning of something much bigger.</p>\n<blockquote>\n<ul>\n<li>Agents and humans organize into specialized groups.</li>\n<li>Agents with tools do much of the work.</li>\n<li>Persisted conversations become the new basis for organizational memory.</li>\n</ul>\n</blockquote>\n<p>Bright futures ahead 🚀</p>\n" }