DEV Community

Cover image for Building a Real-Time Chat Application with Next.js and WebSockets
Dhrumit Kansara
Dhrumit Kansara

Posted on

Building a Real-Time Chat Application with Next.js and WebSockets

Real-time communication has become an essential part of modern web applications. Whether it’s for customer support, team collaboration, or social interaction, real-time chat apps are everywhere. Next.js, combined with WebSockets, provides a powerful solution for building fast, scalable real-time chat applications.

In this blog post, we’ll walk through building a simple real-time chat application using Next.js and WebSockets. You’ll learn how to set up WebSocket communication, manage messages, and create a real-time chat UI with React.

What Are WebSockets?

Before we dive into the code, let's quickly go over WebSockets.

WebSockets provide full-duplex communication channels over a single TCP connection. Unlike traditional HTTP requests, WebSockets allow for continuous bi-directional communication between the client and the server. This makes WebSockets ideal for applications that require real-time data exchange, such as chat apps, live notifications, or collaborative apps.


Prerequisites

To follow along with this tutorial, you should have:

  1. Node.js installed on your system.
  2. A basic understanding of React and Next.js.
  3. Familiarity with WebSockets (though we'll explain the basics as we go).
  4. Socket.IO installed in your project (we’ll use this library to simplify WebSocket communication).

Step 1: Set Up Your Next.js Project

Start by creating a new Next.js project if you don’t have one already:

npx create-next-app real-time-chat
cd real-time-chat
Enter fullscreen mode Exit fullscreen mode

Once the project is set up, install Socket.IO (we’ll use it both for the client and server sides):

npm install socket.io-client socket.io
Enter fullscreen mode Exit fullscreen mode

Step 2: Set Up a WebSocket Server

Now, let’s set up a WebSocket server that will handle the real-time communication. In Next.js, we can use API Routes to create a server-side WebSocket connection.

  1. Inside the pages/api directory, create a new file called chat.js:
mkdir pages/api
touch pages/api/chat.js
Enter fullscreen mode Exit fullscreen mode
  1. Open chat.js and add the following code:
// pages/api/chat.js

import { Server } from 'socket.io';

export default function handler(req, res) {
  if (req.method === 'GET') {
    res.status(200).json({ message: 'Chat API' });
  } else {
    res.status(405).send('Method Not Allowed');
  }
}

export function configureSocket(server) {
  const io = new Server(server, {
    path: '/api/chat',
    cors: {
      origin: '*',
      methods: ['GET', 'POST'],
    },
  });

  io.on('connection', (socket) => {
    console.log('A user connected');

    // Listen for incoming messages
    socket.on('send_message', (message) => {
      io.emit('receive_message', message); // Emit message to all clients
    });

    socket.on('disconnect', () => {
      console.log('A user disconnected');
    });
  });
}
Enter fullscreen mode Exit fullscreen mode

Explanation:

  • Socket.IO Server: We use the socket.io library to create a WebSocket server that listens for incoming connections and messages.
  • CORS Configuration: To allow communication from different origins (client-server), we configure CORS to accept requests from any origin.
  • send_message & receive_message events: The server listens for send_message events and broadcasts the message to all connected clients using the receive_message event.

Next, we need to ensure that the WebSocket server is initialized when Next.js starts up. To do this, we will modify the next.config.js file:

// next.config.js
module.exports = {
  webpack: (config, { isServer }) => {
    if (isServer) {
      const { configureSocket } = require('./pages/api/chat');
      const http = require('http');
      const server = http.createServer(config.server);

      configureSocket(server);
      return config;
    }
    return config;
  },
};
Enter fullscreen mode Exit fullscreen mode

Step 3: Create the Frontend (React & Socket.IO Client)

Now, let’s set up the frontend that communicates with the WebSocket server. We’ll use Socket.IO Client on the frontend to establish a WebSocket connection.

  1. In the pages directory, open index.js (or create a new component if you prefer).

  2. Add the following code to set up the chat UI and WebSocket client logic:

// pages/index.js
import { useState, useEffect, useRef } from 'react';
import io from 'socket.io-client';

export default function Home() {
  const [messages, setMessages] = useState([]);
  const [message, setMessage] = useState('');
  const socketRef = useRef(null);

  useEffect(() => {
    // Initialize WebSocket connection
    socketRef.current = io({
      path: '/api/chat',
    });

    // Listen for incoming messages
    socketRef.current.on('receive_message', (message) => {
      setMessages((prevMessages) => [...prevMessages, message]);
    });

    return () => {
      socketRef.current.disconnect();
    };
  }, []);

  const sendMessage = () => {
    if (message.trim()) {
      socketRef.current.emit('send_message', message);
      setMessage('');
    }
  };

  return (
    <div style={{ maxWidth: '600px', margin: '0 auto', padding: '2rem' }}>
      <h1>Real-Time Chat</h1>
      <div
        style={{
          height: '300px',
          overflowY: 'scroll',
          border: '1px solid #ddd',
          padding: '1rem',
          marginBottom: '1rem',
        }}
      >
        {messages.map((msg, index) => (
          <div key={index}>
            <strong>User:</strong> {msg}
          </div>
        ))}
      </div>
      <input
        type="text"
        placeholder="Type a message"
        value={message}
        onChange={(e) => setMessage(e.target.value)}
        style={{ width: '100%', padding: '0.5rem' }}
      />
      <button onClick={sendMessage} style={{ marginTop: '0.5rem', width: '100%' }}>
        Send
      </button>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

Explanation:

  • Socket.IO Client: We use socket.io-client to establish a WebSocket connection to the server at /api/chat.
  • Messages: The messages state stores the list of chat messages. When a new message is received, we append it to the message list.
  • sendMessage: When the user sends a message, the message is emitted to the server, and once the server responds with the broadcasted message, the message is displayed in the UI.
  • UI: A simple interface with an input field for typing messages and a button to send them.

Step 4: Running the Application

Now that everything is set up, run the application with:

npm run dev
Enter fullscreen mode Exit fullscreen mode

Visit http://localhost:3000 in your browser. Open multiple tabs, and you should see that when you send a message in one tab, it immediately appears in the other tabs in real-time.


Conclusion

Congratulations! You’ve just built a simple real-time chat application using Next.js and WebSockets. By using Socket.IO, we’ve simplified the WebSocket integration for real-time bidirectional communication.

Key Takeaways:

  • WebSockets enable real-time communication between the client and the server.
  • Socket.IO simplifies WebSocket implementation, handling connection, reconnection, and message broadcasting.
  • We used Next.js API Routes to set up the WebSocket server.
  • The application updates in real-time as messages are sent and received.

You can now extend this app with features like:

  • User authentication (using JWT or OAuth).
  • Private messages or group chats.
  • Message persistence with a database (e.g., MongoDB or Firebase).

Real-time chat is just one of the many powerful applications that WebSockets enable. With Next.js and WebSockets, you can create fast, scalable apps that deliver instant experiences to your users.

Happy coding!

Top comments (0)