Learn how to build a real-time chat application using Socket.IO, React, and Express.js. We will cover setting up a server with Express and Socket.IO, creating a client with React, and the fundamentals of message broadcasting.

Before we begin, please make sure you have the following software installed on your system. These tools are essential for developing and running the application we will build:
npm install -g create-vite.Socket.IO is a JavaScript library that enables real-time, bidirectional, event-based communication between web clients and servers. It provides a simple API for sending and receiving messages between clients and servers.
Express.js is a minimal and flexible Node.js framework with a robust set of features for web applications and APIs.
Start by creating a new directory called server and initialize a new npm project:
mkdir server
cd server
npm init -y # Automatically agree to default settings
Install the necessary packages by running: npm install express socket.io cors nodemon.
Create an index.js file with the following server setup:
const express = require("express");
const cors = require("cors");
const app = express();
const port = 3000;
const messages = ["Initial message from server"]; // Holds the messages on the server
// Enabling CORS for any unknown origin
app.use(cors());
const server = app.listen(port, () => {
console.log(`Example app listening on port ${port}`);
});
const io = require("socket.io")(server, { cors: { origin: "*" } });
// Listen for new connection
io.on("connection", (socket) => {
console.log(`User connected ${socket.id}`);
// Send the messages to the client
socket.emit("messages", { messages }); // First parameter is the event name, second is the data
// Listen for new message from the client
socket.on("newMessage", (data) => {
messages.push(data);
io.emit("messages", { messages }); // Send the updated messages to all clients
});
// Listen for disconnection
socket.on(, {
.();
});
});
Socket.IO requires an HTTP server and runs on top of the server created for Express.js.
CORS is configured to allow requests from any origin, which is necessary for development environments where the client and server are hosted separately.
The server listens for client connections. When a client connects, the server sends all stored messages using the messages event.
When the server receives a message through the newMessage event, it stores the message and sends the updated list to all clients.
Once everything is configured, start the server with nodemon index.js.
You can test the server in Postman by selecting the Socket.IO protocol and configuring the event names. The server runs at http://localhost:3000.
React is a popular JavaScript library for building user interfaces. It allows developers to create reusable UI components and manage the state of the application efficiently.
After setting up the server, create the React client application. We will use Vite because it is fast and straightforward. Run npm create vite@latest client -- --template react to create a project in the client folder, then run npm install from that folder. Install the Socket.IO client with npm install socket.io-client and Chakra UI with npm i @chakra-ui/react @emotion/react @emotion/styled framer-motion. Vite includes default CSS, which we will replace in App.js:
import { useEffect, useState } from "react";
import "./App.css";
import openSocket from "socket.io-client";
import {
Container,
Text,
Input,
Button,
ChakraProvider,
Flex,
Stack,
} from "@chakra-ui/react";
function App() {
const [newMessage, setNewMessage] = useState("");
const [messages, setMessages] = useState([]);
const [socket, setSocket] = useState(null);
useEffect(() => {
const socketInstance = openSocket("http://localhost:3000"); // Connect to the server
setSocket(socketInstance);
socketInstance.on("connect", () => {
console.log("Connected to server");
});
socketInstance.on("messages", (data) => {
setMessages(data.messages);
});
return () => {
socketInstance.disconnect(); // Clean up the socket connection
};
}, []);
const handleSendMessage = () => {
socket.(, newMessage);
();
};
(
);
}
;
The useEffect() hook connects to the server and listens for messages. Its cleanup function disconnects when the component unmounts.
When the user clicks Send, the message is sent to the server through the newMessage event. The server stores it and sends the updated message list to all clients.
You can now start the client with npm run dev. Make sure the server is running as well. Open http://localhost:5173/ in multiple browser tabs to see messages update in real time.
Message broadcasting is an important concept in Socket.IO. The difference between socket.emit(), io.emit(), io.on(), and socket.on() is the scope of the message being sent or received.
io.on() listens for events on the global io object, primarily for handling new connections. This is used to handle broader server-level events.
socket.on() listens for events on an individual socket connection. This is used within the context of a specific client connected to the server.
io.emit() sends a message to all clients connected to the server. This is used when you want to broadcast a message to all connected clients simultaneously.
socket.emit() sends a message only to the specific client connected through that socket. This is useful when you want to communicate directly with a single client.
This tutorial showed how to build a simple real-time chat application using Socket.IO, React, and Express.js. We covered setting up a server with Express and Socket.IO, creating a React client, and the fundamentals of message broadcasting.
If you found this tutorial helpful, feel free to share it with others who might benefit from it! And as always, leave comments or questions below if you need further assistance or have suggestions!