Newsletter
Join the Community
Subscribe to our newsletter for the latest news and updates
Minimal Nuxt 5 + Nitro v3 realtime starter with live cursors, presence, and emoji reactions over a single WebSocket.
Nuxt + WebSockets Starter is a boilerplate realtime application built on Nuxt 5 and Nitro v3 that demonstrates live cursors, presence, and emoji reactions over a single WebSocket connection. It is a minimal starter from the Vercel examples repository, designed to show how a Vercel Function can accept a WebSocket upgrade and keep a bidirectional connection open using native crossws pub/sub, with no environment variables, external services, auth, or client SDK.
Nuxt + WebSockets Starter is a minimal realtime starter from the Vercel examples repository that runs on Nuxt 5 with Nitro v3 and uses Nuxt UI for its interface. It produces a WebSocket-based room where every connected browser sees live cursors, presence data, and emoji reactions, all broadcast through a single /api/ws handler. The project targets the Vercel Functions WebSockets beta, but the same handler also runs locally through Nitro's dev server.
experimental.websocket to true in nuxt.config.ts; the same defineWebSocketHandler runs in local dev and production.room topic; cursor moves, reactions, and join/leave events are broadcast with peer.publish from server/api/ws.ts, with no external store.welcome frame on connect, so reconnects rebuild state from scratch.shared/types/realtime.ts defines ClientMessage, ServerMessage, and Peer types that are shared between client and server, keeping message handling in sync.server/utils/identity.ts assigns a name and color to each connection; the page documents swapping this for an authenticated user.welcome frame, with a ping/pong heartbeat detecting half-open connections.LiveCanvas, Cursor, PresenceBar, and HeroBackdrop, with the page composition in app/pages/index.vue and realtime logic in app/composables/useRealtime.ts.Nuxt + WebSockets Starter is for Nuxt developers who want a working reference for WebSocket integration in Nitro v3, including the exact config flag and handler pattern. It is also for Vercel users who want to prototype realtime features on the Vercel Functions WebSockets beta without building infrastructure, and for realtime app builders who need a minimal presence/collaboration foundation to extend with new message types and rooms.
ClientMessage and ServerMessage in shared/types/realtime.ts, then handle it in server/api/ws.ts; the shared types keep client and server in sync.server/utils/identity.ts for authenticated user data.The starter is cloned locally with npx giget@latest gh:vercel/examples/websockets/nuxt my-realtime-app, then installed with pnpm install and started with pnpm dev. On the server side, Nitro v3's WebSocket support is enabled with a single experimental.websocket flag, and the defineWebSocketHandler at /api/ws handles all room logic. On Vercel, the preset's crossws adapter bridges the handler to the runtime's socket upgrade, so there is no Vercel-specific code path or experimental_upgradeWebSocket bridge to maintain.
The project is published under the MIT license. It requires no environment variables or external services, so the only cost is whatever platform you deploy to, such as Vercel Functions with the WebSockets beta.
When a Vercel Function reaches its maximum duration, the WebSocket closes. The client in app/composables/useRealtime.ts reconnects with exponential backoff and reloads the roster from the welcome frame on each new connection. A lightweight ping/pong heartbeat detects half-open connections and forces a reconnect when a pong is missed.
Add a variant to ClientMessage and ServerMessage in shared/types/realtime.ts, then handle it in the handler at server/api/ws.ts. Because the types are shared between client and server, both sides stay in sync automatically.
Yes. Locally, Nitro's dev server handles the WebSocket at the same /api/ws endpoint, and the same handler works in any environment supported by crossws, not just Vercel.
No. It intentionally has no auth and no client SDK; identity is anonymous per connection, generated in server/utils/identity.ts, and can be replaced with an authenticated user.
