Features • Demo • Architecture • Tech Stack • Getting Started • Configuration • Deployment • Contributing • License
SocketXO is a high-performance, browser-based real-time Tic-Tac-Toe web application. It is built specifically to demonstrate production-grade real-time system behavior, focusing heavily on connection resilience, server-authoritative state, and deterministic state synchronization over Socket.io.
- The "Disconnect Handshake" — A highly resilient recovery system. If a player disconnects, the server holds their seat for a 30-second grace period while notifying the opponent. State is instantly restored upon return.
- Server-Authoritative State Engine — The backend enforces 100% synchronization consistency with zero desync incidents. Invalid moves are strictly rejected.
- Frictionless Matchmaking — Instant guest identity creation and a global matchmaking queue that pairs players in under 2 seconds.
- Room-Scoped Real-Time Chat — In-game chat drawer sanitized against XSS for secure communication between players.
- AI Benchmark Mode — Deterministic Minimax AI mode for testing game logic correctness.
- Dev-Mode Chaos Controls — A hidden mission control dashboard to intentionally simulate lag and disconnects.
Demonstrating multi-client synchronization and managed recovery during network loss.
socket-xo-online.mp4
Tip
This recording showcases the managed 30-second grace period where the server holds the session, notifies the opponent, and restores the full board state upon reconnection.
Demonstrating the deterministic Minimax engine.
socket-xo-ai.mp4
| Layer | Technology |
|---|---|
| Frontend | React 19.x, Vite 7.x, React Router v7 |
| Backend | Node.js 20+, Express, Socket.io 4.x |
| Database | strictly in-memory data architecture |
| Testing/Infra | Vitest, Playwright |
SocketXO is built with a state-first, server-authoritative architecture. The system ensures that all clients are perfectly synchronized by treating the backend as the single source of truth for game logic and session state.
- Event-Driven Core: Real-time communication is handled via Socket.io, with a strict event contract defined in the
shared/package. - Session-Based Identity: Players are identified by a persistent unique ID rather than their socket connection, allowing for seamless recovery across page refreshes or network drops.
- Reactive State Sync: The frontend uses a reactive approach, where UI components instantly update based on the server-broadcasted state.
The centerpiece of SocketXO's reliability is its Disconnect Handshake mechanism. Unlike typical socket apps where a disconnect ends the session, SocketXO enters a managed recovery state.
sequenceDiagram
participant P1 as Player A
participant S as Server
participant P2 as Player B
Note over P1, P2: Active Game Playing
P1-xS: Connection Lost
S->>S: Start 30s Grace Timer
S->>P2: Emit 'player_disconnected'
Note right of P2: UI shows "Opponent Disconnected"
alt Reconnect within 30s
P1->>S: Reconnect with ReconnectToken
S->>S: Validate Token & Rebind Session
S->>S: Cancel Grace Timer
S->>P1: Emit 'reconnect_success'
S->>P2: Emit 'player_reconnected'
S->>P1: Sync full Game State
else Grace Timer Expires
S->>S: Abandon Room
S->>P2: Emit 'game_over' (Opponent Left)
end
- Authoritative Validation: The game engine on the server validates every move against the current board state and player turns before broadcasting updates.
- Atomic State Updates: State transitions are atomic, preventing race conditions where two players might attempt to claim the same square simultaneously.
- Cryptographic Session Tokens: Reconnections are secured using short-lived tokens, preventing session hijacking.
- Node.js v20 or higher
- npm
-
Clone the repository
git clone https://github.com/RusithHansana/socket-xo.git cd socket-xo -
Install dependencies
npm install
-
Configure environment variables
cp .env.example .env
See Configuration for details.
-
Start the development server
npm run dev
SocketXO uses environment variables for both the server and client. Copy the example file to get started:
cp .env.example .env| Variable | Description | Default | Requirement |
|---|---|---|---|
PORT |
The port the Node server will listen on | 3001 |
Optional |
NODE_ENV |
Environment mode (development, production, test) |
development |
Optional |
CORS_ORIGIN |
Allowed origin for Socket.io (should match client URL) | http://localhost:5173 |
Required in Prod |
GRACE_PERIOD_MS |
Delay before a disconnected room is abandoned (ms) | 30000 |
Optional |
CLEANUP_INTERVAL_MS |
Frequency of stale room cleanup (ms) | 60000 |
Optional |
VITE_DEV_MODE |
Enable developer tools and Mission Control UI | true |
Optional |
In a production environment, SocketXO is designed to run as a single, unified Node.js application that serves both the API/WebSocket server and the built React frontend.
To prepare the project for deployment, follow these build steps in order:
-
Build Shared Types: Ensure the contract between client and server is prepared.
npm run build --workspace=shared
-
Build Client: Generate the optimized production bundle for the React frontend.
npm run build --workspace=client
-
Build Server: Compile the TypeScript backend.
npm run build --workspace=server
Once built, you can start the production server:
export NODE_ENV=production
export CORS_ORIGIN=https://your-domain.com
npm startDeploying to Render (Recommended)
Render is the recommended platform for hosting SocketXO due to its native support for Node.js and WebSockets.
- Create a New Web Service: Connect your GitHub repository.
- Environment: Select
Node. - Region: Choose a region close to your target users for lower latency.
- Build Command:
npm install && npm run build - Start Command:
npm start - Environment Variables: Add the following in the Render dashboard:
NODE_ENV:productionCORS_ORIGIN:https://your-app-name.onrender.com
When NODE_ENV=production is set, the backend acts as a unified host:
- Serves the static assets from
client/dist. - Routes all non-socket/API requests to the React
index.html(SPA routing). - Listens for WebSocket connections on the same port.
Important
Cold Starts: Render's free tier spins down after 15 minutes of inactivity. The first visitor after a quiet period will experience a 30-60 second delay while the server wakes up. During this time, Socket.io connections will be established once the server is fully ready.
| Provider | Pros | Cons |
|---|---|---|
| Railway | Seamless DX and monorepo detection | Limited free credits per month |
| Koyeb | High-performance with global edge | Smaller community/ecosystem |
| Fly.io | Best latency and persistent sockets | Requires credit card & Docker setup |
socket-xo/
├── client/ # The Vite React frontend
├── server/ # The Node.js/Socket.io backend engine
├── shared/ # Shared TypeScript types and Socket.io event contracts
├── tests/ # E2E and Acceptance Tests
└── ...
Contributions are always welcome!
Please read our Contributing Guide to learn about our development process, how to propose bugfixes and improvements, and how to build and test your changes.
This project has adopted the Contributor Covenant Code of Conduct. By participating, you are expected to uphold this code.
This project is licensed under the MIT License.
- React & Vite — Frontend library and build tool
- Socket.io — Real-time bidirectional event-based communication
- Node.js & Express — Backend runtime and web framework
- TypeScript — Type-safe development
- React Router — Client-side navigation
- Vitest — Unit and integration testing
- Playwright — End-to-end testing
- DOMPurify — XSS sanitization for real-time chat
- Pino — High-performance JSON logging
Built with ☕ by RusithHansana

