A real-time multi-user chat application demonstrating the integration of Cap'n Web RPC with TanStack Start. This project showcases bidirectional WebSocket communication, server-side rendering, and modern React patterns.
- Real-time messaging - Instant message delivery across all connected users
- Online presence - See who's currently in the chat
- Auto-connection - Seamlessly connects when the page loads
- Responsive design - Works on desktop and mobile devices
- Modern chat UI - Messages appear like iMessage/WhatsApp (yours on right, others on left)
- Username-based - Simple username entry, no registration required
This demo combines several powerful technologies:
- Cap'n Web RPC - Bidirectional RPC over WebSockets
- TanStack Start - Full-stack React framework
- TanStack Router - Type-safe routing
- Tailwind CSS - Utility-first styling
- WebSocket Server - Real-time communication layer
chat-server/
├── chat-logic.ts # Core chat business logic
├── capnweb-rpc.ts # Cap'n Web RPC server implementation
└── vite-plugin.ts # WebSocket integration with Vite
src/
├── components/
│ ├── ChatInterface.tsx # Main chat message display
│ ├── OnlineUsers.tsx # Online user list
│ └── UsernameInput.tsx # Username entry
├── hooks/
│ ├── useChatConnection.ts # WebSocket connection management
│ └── useChatMessages.ts # Message state and polling
└── routes/
└── index.tsx # Main chat page
- Node.js 18+
- pnpm (recommended) or npm
# Clone the repository
git clone <repo-url>
cd capnweb-chat-demo
# Install dependencies
pnpm install# Start the development server
pnpm devOpen http://localhost:3000 in multiple browser tabs to test the chat functionality.
# Build the application
pnpm build
# Start production server
pnpm start- User opens the chat page
- Application auto-connects to WebSocket server via Cap'n Web RPC
- Connection status is managed transparently
- User enters a username
- Application automatically joins the chat room
- Messages are sent via RPC calls to the server
- Server broadcasts messages to all connected users
- Client polls for new messages every second
// Server-side message broadcasting
await ChatServer.broadcastToAll({
type: 'message',
message: message.message,
username: message.username,
timestamp: message.timestamp,
id: message.id,
})- Messages: Polled every 1 second
- Online users: Updated every 5 seconds
- Connection status: Real-time via WebSocket events
The WebSocket server is configured in chat-server/vite-plugin.ts:
// WebSocket endpoint: /api/websocket
wss.handleUpgrade(request, socket, head, (ws) => {
const chatServer = new ChatServer()
chatServer.setWebSocket(ws)
newWebSocketRpcSession(ws, chatServer)
})Messages are queued per user to ensure delivery:
// Each user gets their own message queue
export const userMessageQueues = new Map<string, Array<any>>()
// Messages are polled and cleared
const messages = userMessageQueues.get(username) || []
userMessageQueues.set(username, []) // Clear after reading# Run tests
pnpm testTo test the chat functionality:
- Open multiple browser tabs to http://localhost:3000
- Enter different usernames in each tab
- Send messages and observe real-time delivery
- Check the online users list updates
- Bidirectional: Both client and server can call methods on each other
- Type-safe: Full TypeScript support for RPC calls
- WebSocket-based: Built on standard WebSocket protocol
- Efficient: Binary protocol with message queuing
- Full-stack: Single framework for client and server
- Server-side rendering: Pages render on the server first
- File-based routing: Routes defined by file structure
- Type-safe: End-to-end TypeScript support
User types message
↓
useChatMessages.sendMessage()
↓
Cap'n Web RPC call
↓
ChatServer.sendMessage()
↓
ChatLogic.sendMessage()
↓
Broadcast to all users
↓
Message queues updated
↓
Clients poll for updates
↓
UI updates with new message
This application demonstrates:
- Real-world WebSocket usage - Not just a simple echo server
- RPC over WebSockets - More structured than plain message passing
- Modern React patterns - Hooks, effects, and clean component architecture
- Full-stack TypeScript - Shared types between client and server
- Production-ready patterns - Error handling, reconnection, message queuing
Perfect for learning how to build real-time applications with modern web technologies!
This is a demonstration project, but improvements are welcome:
- Enhanced error handling
- Message persistence
- User authentication
- Private messaging
- File sharing
- Emoji reactions
This project is open source and available under the MIT License.
Built with ❤️ using Cap'n Web RPC and TanStack Start
