Realtime chat (Next.js + WebSockets on Vercel)
A single global chat room built on WebSockets on Vercel Functions: live user count, typing indicators, and realtime messages, with a deterministic boring-avatars avatar per user and the last ~50 messages replayed on join.
How it works
app/api/ws/route.tsupgrades the request to a WebSocket withexperimental_upgradeWebSocket()from@vercel/functions.lib/chat.tsis the hub. A connection is pinned to one Function instance, so it broadcasts to local sockets immediately and fans out across instances through Redis. A single ioredis client handles writes and presence; a duplicated connection runs a blockingXREADto receive other instances' messages in realtime.- Redis keys:
chat:conns+chat:connmeta(presence, deduped byclientId),chat:messages(durable log + history),chat:typing(transient relay). app/components/ChatRoom.tsxowns per-tab identity (crypto.randomUUID()+ name insessionStorage);Chat.tsxopens the socket, renders the room, and reconnects with backoff.
Redis is optional: without REDIS_URL the app runs as a single in-memory instance (no history, no cross-instance delivery).
Run locally
WebSocket upgrades need the Vercel runtime, so start the app with the Vercel CLI:
vercel devOpen http://localhost:3000 in two tabs (each tab is a distinct user). pnpm dev:next runs plain next dev for UI work, but the WebSocket route won't function there.
Redis
Add Upstash Redis from the Vercel Marketplace, then pull the credentials:
vercel env pull .env.localThis sets REDIS_URL — the connection string the ioredis client uses.
Deploy
Deploy to Vercel. WebSockets require Fluid Compute, the default for projects created on or after April 23, 2025.