Real-time features — chat, live presence, instant notifications — make a product feel alive. They also catch teams out, because the request/response model most apps use doesn't fit. Here's the clean approach we use to add real-time to a Next.js product without the pain.
1. Why you need a socket layer
Normal HTTP is one-shot: the client asks, the server answers. Chat needs the server to push to clients at any time. That's a persistent connection — WebSockets — and Socket.IO makes them reliable with fallbacks and reconnection built in.
2. The server: rooms and broadcasts
import { Server } from "socket.io"; const io = new Server(4000, { cors: { origin: process.env.APP_URL } }); io.on("connection", (socket) => { socket.on("join", (roomId) => socket.join(roomId)); socket.on("message", async ({ roomId, text, userId }) => { const msg = await saveMessage({ roomId, text, userId }); io.to(roomId).emit("message", msg); // push to everyone in the room });});3. The client: a tiny hook
import { useEffect, useState } from "react";import { io } from "socket.io-client"; const socket = io(process.env.NEXT_PUBLIC_SOCKET_URL!); export function useChat(roomId: string) { const [messages, setMessages] = useState([]); useEffect(() => { socket.emit("join", roomId); socket.on("message", (m) => setMessages((p) => [...p, m])); return () => { socket.off("message"); }; }, [roomId]); const send = (text, userId) => socket.emit("message", { roomId, text, userId }); return { messages, send };}4. Scaling it
- ✓Persist messages to the database (don't trust memory)
- ✓Use a Redis adapter so multiple server instances share events
- ✓Add presence (online/typing) via lightweight events
- ✓Authenticate the socket connection, not just the page
- Estimated timeline
- 2–6 weeks
- Best for
- Chat, support, collaboration, live data
- Related service
- Real-time Applications
Need this built? Explore our Real-time Applications service.
View service →Written by WeBuildCrew Team · Published 10 January 2026 · 9 min read