Skip to content
New Project

Nitro + WebSockets Starter

Realtime live cursors, presence, and emoji reactions over a WebSocket.

DeployView Demo

Nitro + WebSockets Starter

Minimal realtime starter built with Nitro v3, React, shadcn/ui (on Base UI primitives), and the Vercel Functions WebSockets beta. Move your cursor and everyone in the room sees it live — presence, cursors, and emoji reactions over a single WebSocket connection. No auth, no client SDK.

Deploy

No environment variables and no external services — the realtime layer runs entirely on native WebSocket pub/sub (see How it works).

Run locally

npx giget@latest gh:vercel/examples/websockets/nitro my-realtime-app
cd my-realtime-app
pnpm install
pnpm dev

Open http://localhost:3000 in two browser tabs (or share the URL) to see live cursors, presence, and reactions.

How it works

A Vercel Function can accept a WebSocket upgrade and keep a bidirectional connection open. Nitro v3 ships native WebSocket support powered by crossws, enabled with a single flag:

// vite.config.ts
nitro({ features: { websocket: true } })

The headline: one transport, every environment. The same defineWebSocketHandler (server/api/ws.ts) at /api/ws powers local dev and production — locally through Nitro's dev server, on Vercel through the preset's crossws/adapters/vercel bridge, which hands the handler the runtime's socket upgrade. There's no Vercel-specific code path and no experimental_upgradeWebSocket bridge to maintain.

All room logic lives in the handler (server/api/ws.ts) itself.

State and pub/sub

Each connection subscribes to a single room topic. Cursor moves, reactions, and join/leave events are broadcast with crossws's native peer.publish (server/api/ws.ts) — no external store and no client SDK. The connected roster is held in memory and replayed to each client in the welcome frame on connect, so a reconnect rebuilds it from scratch.

Architecture

app/ # React SPA (Vite)
├── App.tsx # page composition
├── hooks/use-realtime.ts # connection, reconnect, heartbeat
├── components/ # LiveCanvas, Cursor, PresenceBar, HeroBackdrop
└── components/ui/ # shadcn/ui primitives (Base UI)
shared/
└── types/realtime.ts # ClientMessage / ServerMessage / Peer — the wire protocol
server/
├── api/ws.ts # /api/ws — native WebSocket handler + room pub/sub
└── utils/
└── identity.ts # anonymous identity (name + color) per connection

The frontend and the Nitro server are wired together by the nitro/vite plugin: index.html is served as the SPA renderer for all unmatched routes, and server/ routes (like /api/ws) are matched first.

Reconnects

WebSocket connections close when a Vercel Function reaches its maximum duration. The client reconnects with exponential backoff and reloads the roster from the welcome frame on each new connection — see use-realtime.ts.

A lightweight heartbeat (ping/pong) runs over the same socket so the client can detect a half-open connection (a missed pong) and force a reconnect. On disconnect, the server's close/error handlers publish a leave frame so the peer drops from everyone's roster.

Adapting this starter

  • Identity — swap the anonymous name/color in server/utils/identity.ts for your authenticated user.
  • New message types — add a variant to ClientMessage / ServerMessage in shared/types/realtime.ts, then handle it in the handler server/api/ws.ts. The types are shared, so the client and server stay in sync.
  • Rooms — key the topic by a room id to isolate multiple rooms. Nitro also derives a pub/sub namespace from the connection path, so per-room routes work out of the box.
  • More components — the UI primitives are shadcn/ui built on Base UI. Copy more from the Base UI component docs, or scaffold a fresh project with pnpm dlx shadcn@latest init -b base to generate them.

Links

  • Vercel WebSockets docs
  • Nitro WebSocket docs
  • Nitro Vite plugin
  • shadcn/ui
  • Base UI

License

Published under the MIT license.

GitHub
Ownervercel
Repositoryexamples
Use Cases
Starter
Stack
Nitro
React
Tailwind

Related Templates

Next.js Boilerplate

Get started with Next.js and React in seconds.
Next.js Boilerplate thumbnail

Image Gallery Starter

An image gallery built on Next.js and Vercel Blob.
Image Gallery Starter thumbnail

Chatbot

A full-featured, hackable Next.js AI chatbot built by Vercel
Chatbot thumbnail
DeployView Demo