Back to templates

Template details

Nitro + WebSockets Starter

Realtime live cursors, presence, and emoji reactions over a WebSocket, built with Nitro v3, React, and shadcn/ui.

About this template

The Nitro + WebSockets Starter is a realtime boilerplate from the Vercel examples repository that demonstrates live presence, shared cursors, and emoji reactions over a single WebSocket connection, built with Nitro v3, React, and shadcn/ui.

What is the Nitro + WebSockets Starter?

This starter ships a minimal realtime app: a React single-page application (Vite) on the frontend and a Nitro v3 server with native WebSocket support, powered by crossws, on the backend. It takes a WebSocket connection at /api/ws and produces a live collaborative room where every client sees cursor movements, join/leave events, and emoji reactions. The realtime layer runs entirely on Vercel Functions using the WebSockets beta, with no environment variables and no external services. The project is published under the MIT license as part of the official Vercel examples repository.

Key Features

  • Native WebSocket handling — A single defineWebSocketHandler in server/api/ws.ts works in local dev and production; on Vercel the preset's crossws/adapters/vercel bridge handles the upgrade, so there is no Vercel-specific code path.
  • Room-based pub/sub — Every connection subscribes to one room topic, and events like cursor moves and reactions are broadcast with crossws's peer.publish — no external store and no client SDK.
  • Shared TypeScript wire protocol — shared/types/realtime.ts defines ClientMessage, ServerMessage, and Peer types used by both client and server, keeping message handling in sync.
  • Reconnect with exponential backoff — On disconnect, the client reconnects automatically and reloads the roster from the welcome frame; a heartbeat (ping/pong) detects half-open connections and forces a reconnect.
  • Anonymous per-connection identity — server/utils/identity.ts generates a name and color for each client, replaceable with an authenticated user for production.
  • Room isolation from the path — Nitro derives a pub/sub namespace from the connection path, so per-room routes work out of the box.
  • shadcn/ui on Base UI primitives — UI components are shadcn/ui components built on Base UI, and a fresh project can be scaffolded with pnpm dlx shadcn@latest init -b base.
  • One-command scaffolding — Clone the starter with npx giget@latest gh:vercel/examples/websockets/nitro my-realtime-app, then run pnpm install && pnpm dev.

Who is it for?

  • Developers new to WebSockets on Vercel — Use this starter to see a working WebSocket upgrade and realtime pub/sub pattern without managing separate infrastructure.
  • Teams adding collaborative features to React apps — Extend the existing ClientMessage and ServerMessage variants to add custom realtime interactions such as chat or drawing.
  • Nitro users exploring the Vite plugin — See how the nitro/vite plugin serves the React SPA for unmatched routes while matching server routes like /api/ws first.

What can you do with it?

  • Create a realtime demo — Launch the app in two browser tabs and watch live cursors, presence, and emoji reactions over a single WebSocket.
  • Prototype collaborative tools — Add new message types to the shared wire protocol and handle them in server/api/ws.ts to build features like shared whiteboards or multi-user forms.
  • Build multi-room applications — Key the pub/sub topic by a room id or rely on the path-derived namespace to isolate rooms, enabling per-URL chat or telepresence.

How does it work?

A Vercel Function accepts a WebSocket upgrade and keeps the connection open. Nitro v3 enables the feature with one flag in vite.config.ts: nitro({ features: { websocket: true } }). The handler at server/api/ws.ts manages subscriptions, broadcasts with peer.publish, and sends a welcome frame containing the current roster when a client connects.

FAQ

Is the Nitro + WebSockets Starter free?

Yes. The source is part of the vercel/examples repository and is released under the MIT license. Deploying to Vercel uses the Vercel Functions WebSockets beta; there are no paid add-ons or API keys required for the realtime layer.

Does it require a realtime client SDK?

No. The frontend's use-realtime.ts hook opens a WebSocket directly to /api/ws and parses the custom message types. The only dependency for realtime is the browser's native WebSocket API.

What happens when a Vercel Function reaches its maximum duration?

The WebSocket connection closes. The client automatically reconnects with exponential backoff and rebuilds the roster from the welcome frame on each new connection, so the app recovers without manual refresh.

Can I add authentication?

Yes. Replace the anonymous identity logic in server/utils/identity.ts with your authenticated user, and add any token checks you need in the WebSocket handler or upgrade step.

screenshot of Nitro + WebSockets Starter on template0.com