Real-Time Chat App with MERN and Socket.IO
MERN | Nexsaar
1. Introduction
Real-time chat applications have become essential in modern web development, whether for messaging platforms, customer support systems, or collaborative tools. The MERN stack (MongoDB, Express.js, React, Node.js) combined with Socket.IO enables developers to build scalable, real-time communication apps with ease. This blog will provide a step-by-step guide to building a real-time chat app, complete with backend and frontend integration.

Key Concepts of Real-Time Communication
-
WebSockets: A communication protocol that provides full-duplex channels over a single TCP connection.
-
Socket.IO: A JavaScript library that abstracts WebSocket handling, adding fallbacks, rooms, namespaces, and reliability.
-
MERN Stack: Combines MongoDB, Express, React, and Node.js to provide a full-stack environment.
Project Setup
Initialize the project and install dependencies:
mkdir chat-app && cd chat-app
npm init -y
npm install express socket.io mongoose cors dotenv
npx create-react-app client
cd client && npm install redux react-redux @reduxjs/toolkit socket.io-client axiosBackend with Node.js, Express, MongoDB, and Socket.IO
Let’s configure the backend server that connects to MongoDB and enables Socket.IO for real-time communication.
const express = require('express');
const http = require('http');
const socketIo = require('socket.io');
const mongoose = require('mongoose');
const cors = require('cors');
require('dotenv').config();
const app = express();
const server = http.createServer(app);
const io = socketIo(server, { cors: { origin: '*' } });
app.use(cors());
app.use(express.json());
// MongoDB Connection
mongoose.connect(process.env.MONGO_URI, { useNewUrlParser: true, useUnifiedTopology: true })
.then(() => console.log('MongoDB connected'))
.catch((err) => console.log(err));
// Message Schema
const messageSchema = new mongoose.Schema({
user: String,
content: String,
timestamp: { type: Date, default: Date.now }
});
const Message = mongoose.model('Message', messageSchema);
// Socket.IO Events
io.on('connection', (socket) => {
console.log('User connected:', socket.id);
socket.on('sendMessage', async (data) => {
const newMessage = new Message(data);
await newMessage.save();
io.emit('receiveMessage', newMessage);
});
socket.on('disconnect', () => {
console.log('User disconnected');
});
});
server.listen(5000, () => console.log('Server running on port 5000'));Frontend with React, Redux, and Socket.IO Client
The frontend connects to the backend and renders chat messages in real-time. Redux is used for state management.
import React, { useState, useEffect } from 'react';
import io from 'socket.io-client';
import { useDispatch, useSelector } from 'react-redux';
import { addMessage, setMessages } from './messageSlice';
const socket = io('http://localhost:5000');
function ChatApp() {
const [message, setMessage] = useState('');
const dispatch = useDispatch();
const messages = useSelector((state) => state.messages);
useEffect(() => {
socket.on('receiveMessage', (msg) => {
dispatch(addMessage(msg));
});
}, [dispatch]);
const sendMessage = () => {
const msgData = { user: 'User1', content: message };
socket.emit('sendMessage', msgData);
setMessage('');
};
return (
<div>
<h2>Real-Time Chat</h2>
<div
style={{ border: '1px solid #ccc', height: '300px', overflowY: 'scroll' }}
>
{messages.map((msg, index) => (
<p key={index}>
<strong>{msg.user}:</strong> {msg.content}
</p>
))}
</div>
<input value={message} onChange={(e) => setMessage(e.target.value)} />
<button onClick={sendMessage}>Send</button>
</div>
); }
export default ChatApp;Redux Slice for Messages
import { createSlice } from '@reduxjs/toolkit';
const messageSlice = createSlice({
name: 'messages',
initialState: [],
reducers: {
addMessage: (state, action) => {
state.push(action.payload);
},
setMessages: (state, action) => {
return action.payload;
}
}
});
export const { addMessage, setMessages } = messageSlice.actions;
export default messageSlice.reducer;Enhancements to Add
-
User authentication (JWT-based)
-
Private messaging with Socket.IO rooms
-
Typing indicators
-
Online/offline user tracking
-
File/image sharing
-
Deployment with services like Heroku, Vercel, or AWS
Conclusion
By combining MERN with Socket.IO, we can build scalable, feature-rich real-time chat apps. This setup can be extended with authentication, private chats, notifications, and more. The combination of WebSockets and MERN makes building modern, real-time applications easier than ever.