Build a Basic Chat Application using the MERN Stack

Traducciones al Español
Estamos traduciendo nuestros guías y tutoriales al Español. Es posible que usted esté viendo una traducción generada automáticamente. Estamos trabajando con traductores profesionales para verificar las traducciones de nuestro sitio web. Este proyecto es un trabajo en curso.
Create a Linode account to try this guide with a $ credit.
This credit will be applied to any valid services used during your first  days.

MERN is a modern web application development stack consisting of MongoDB, Express JS, React, and Node.js. Its bundle of robust and well-supported open-source software provides a solid foundation for building a wide range of web applications.

The MERN stack has the advantage of using React. Other variants exist, like the MEAN stack (which uses Angular) and the MEVN stack (which uses Vue). But with React, you get the advantage of server-side rendering and improved availability for web crawlers.

This MERN tutorial helps you get started building a MERN app of your own for an Ubuntu 20.04 or Debian 10 server.

Before You Begin

  1. Familiarize yourself with our Getting Started with Linode guide, and complete the steps for setting your Linode’s hostname and timezone.

  2. This guide uses sudo wherever possible. Complete the sections of our How to Secure Your Server guide to create a standard user account, harden SSH access, and remove unnecessary network services.

  3. Update your system using the following command:

    sudo apt update && sudo apt upgrade
Note
The steps in this guide are written for non-root users. Commands that require elevated privileges are prefixed with sudo. If you’re not familiar with the sudo command, see the Linux Users and Groups guide.

What Is MERN Stack?

A MERN architecture is a full-stack framework for developing modern web applications. It is a variation of the MEAN stack but replaces Angular (the A) with React.

A MERN stack is made up of the following components:

Each of these technologies is well-supported and offers robust features. This makes a MERN stack a good choice for developing new web applications.

How to Develop a MERN App

This section walks you through installing MongoDB and Node.js then setting up an Express JS server and React frontend. By the end, you have a complete MERN app, ready to be customized and expanded to your needs.

After building the application, the last section of this guide shows you how to start up your MERN stack and test it out.

Install the Prerequisites

Two of the MERN components should be installed before you start on your project: MongoDB and Node.js. Once you have them installed, you can create a project, where you install Express JS and React as dependencies.

Install MongoDB

  1. Install gnupg using the following command:

    sudo apt install gnupg
  2. Import the GPG key for MongoDB.

    wget -qO - https://www.mongodb.org/static/pgp/server-5.0.asc | sudo apt-key add -
  3. Add the MongoDB package list to APT.

    echo "deb http://repo.mongodb.org/apt/debian buster/mongodb-org/5.0 main" | sudo tee /etc/apt/sources.list.d/mongodb-org-5.0.list
    echo "deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu focal/mongodb-org/5.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-5.0.list
  4. Update the APT package index using the following command:

    sudo apt update
  5. Install MongoDB using the following command:

    sudo apt install mongodb-org

See the official documentation for more on installing MongoDB on Debian and on Ubuntu. You can also refer to our How To Install MongoDB on Ubuntu 16.04 guide.

Install Node.js

  1. Install the Node Version Manager, the preferred method for installing Node.js.

    curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash
  2. Restart your shell session (logging out and logging back in), or run the following commands:

    export NVM_DIR="$HOME/.nvm"
    [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
    [ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"
  3. Install the current version of Node.js:

    nvm install node

You can additionally refer to our How to Install and Use the Node Package Manager (NPM) on Linux guide.

Developing the App

The MERN app project itself consists of two components:

  • Express JS provides the backend web API, connecting to MongoDB to store and retrieve data
  • React provides the frontend, giving the user interface for interacting with the application

The next sections show you how to set these up for a basic chat application.

Create the Express JS Server

  1. Create a directory for your project, and then a subdirectory for your Express JS server. Then, change into the Express JS subdirectory.

    This example creates a project directory under the current user’s home directory and an Express JS subdirectory named server.

    mkdir -p ~/example-mern-app/server
    cd ~/example-mern-app/server
  2. Initialize a Node.js project, and install Express JS. At the same time, install the Mongoose module for working with MongoDB:

    npm init -y
    npm install --save express mongoose
  3. Create an index.js file, and give it the contents shown below. The purpose of each part of this code is elaborated in comments within the code:

    File: index.js
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    
    // Set up ExpressJS.
    const express = require("express");
    const bodyParser = require('body-parser');
    const app = express();
    const router = express.Router();
    const port = 5000;
    
    // Set up Mongoose.
    const mongoose = require('mongoose');
    const mongoDbUrl = 'mongodb://127.0.0.1/example_database';
    
    // Import MongoDB models.
    const MessageModel = require('./models/message.js');
    
    // Connect to the database.
    mongoose
      .connect(mongoDbUrl, {useNewUrlParser: true, useUnifiedTopology: true})
      .then(() => console.log('Database connection established.'))
      .catch((err) => console.log('Database connection error: ' + err))
    mongoose.Promise = global.Promise;
    
    // Prevent possible cross-origin issues.
    app.use((req, res, next) => {
      res.header('Access-Control-Allow-Origin', '*');
      res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept');
      next();
    });
    
    // Necessary to handle the JSON data.
    app.use(bodyParser.json());
    
    // Create endpoints for the frontend to access.
    app.get('/messages', (req, res, next) => {
      MessageModel
        .find({}, 'messageText')
        .then((data) => res.json(data))
        .catch(next);
    });
    
    app.post('/messages', (req, res, next) => {
      if (req.body.messageText) {
        MessageModel.create(req.body)
          .then((data) => res.json(data))
          .catch(next);
      } else {
        res.json({error: "Please provide message text."});
      }
    });
    
    // Listen on the port.
    app.listen(port, () => {
      console.log(`Server is running on port: ${port}`);
    });

    You can, alternatively, download the above file directly.

  4. Create a models directory, and create a message.js file in it. Give the file the following contents:

    File: models/message.js
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    
    // Set up Mongoose.
    const mongoose = require('mongoose');
    const Schema = mongoose.Schema;
    
    // Create a schema to be used for the MessageModel.
    const MessageSchema = new Schema({
      messageText: {
        type: String,
        required: [true, 'This fields is required.'],
      },
    });
    
    // Create the message model from the MessageSchema.
    const MessageModel = mongoose.model('message', MessageSchema);
    
    module.exports = MessageModel;

    As above, you can also download this file directly.

  5. To verify that everything is working, start the MongoDB service and run the Express JS server with the following commands:

    sudo systemctl start mongod
    node index.js

    Upon execution of the commands above, you should observe the following output:

    Server is running on port: 5000
    Database connection established.
  6. You can make sure that the endpoints are working with the following two cURL commands:

    curl -X POST -H "Content-Type: application/json" -d '{"messageText":"This is a test."}' localhost:5000/messages
    curl localhost:5000/messages

    Upon execution of the commands above, you should observe the following output:

    [{"_id":"61784e4251b2842f3ffe6eaf", "messageText":"This is a test."}]

    Once you have seen that the server is working, you can stop it with the Ctrl + C combination.

  7. To run the Express JS server and React simultaneously, the Start MERN Stack Services section below uses the concurrently Node.js module. Install the module using the command below:

    npm install --save-dev concurrently
  8. Open the package.json file, and change the scripts portion as shown below. This allows you to start the server and frontend simultaneously with a single command:

    File: package.json
    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    {
      //...
      "scripts": {
        "server": "node index.js",
        "client": "cd ../client && npm start",
        "app_stack": "concurrently \"npm run server\" \"npm run client\""
      },
      //...
    }

You can learn more about getting started with Express JS in our guide Express JS Tutorial: Get Started Building a Website.

Create the React Frontend

  1. Change into the main project directory, and use the React project creation tool to initialize a React app. This example names the React project client.

    cd ~/example-mern-app
    npx create-react-app client
  2. Change into the new React directory, and install the axios module. This facilitates making requests from the frontend to the Express JS server.

    npm install --save axios
  3. Open the App.js file, and give it the contents shown below. This requires you to delete the file’s existing contents. You can find comments throughout the code elaborating on each part.

    File: App.js
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    
    // Import React and the stylesheet.
    import React from 'react';
    import './App.css';
    
    // Import the component to be used for fetching, posting,
    // and displaying messages from the server.
    import Messages from './Messages';
    
    // Initialize the application display, giving a
    // placeholder for the Messages component.
    function App() {
      return (
        <div className="App">
          <Messages />
        </div>
      );
    }
    
    export default App;

    You can also download this file directly.

  4. Create a Messages.js file, and give it the contents shown below:

    File: Messages.js
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    
    // Import React's Component and Axios.
    import React, { Component } from 'react';
    import axios from 'axios';
    
    // Create the component for handling messages.
    class Messages extends Component {
      // Create an object to hold the list of messages and the message
      // being prepared for sending.
      state = {
        list: [],
        toSend: ""
      };
    
      // When the component loads, get existing messages from the server.
      componentDidMount() {
        this.fetchMessages();
      }
    
      // Get messages from the server.
      fetchMessages = () => {
        axios
          .get('/messages')
          .then((res) => {
            if (res.data) {
              this.setState({ list: res.data, toSend: "" });
              let inputField = document.getElementById("textInputField");
              inputField.value = "";
            } else {
              this.setState({ list: ["No messages!"] });
            }
          })
          .catch((err) => console.log(err));
      }
    
      // Post new messages to the server, and make a call to update
      // the list of messages.
      sendMessage = () => {
        if (this.state.toSend === "") {
          console.log("Enter message text.")
        } else {
          axios
            .post('/messages', { messageText: this.state.toSend })
            .then((res) => {
              if (res.data) {
                this.fetchMessages();
              }
            })
            .catch((err) => console.log(err));
        }
      }
    
      // Display the list of messages.
      listMessages = () => {
        if (this.state.list && this.state.list.length > 0) {
          return (this.state.list.map((message) => {
            return (
              <p>{message.messageText}</p>
            );
          }))
        } else {
          return (<p>No messages!</p>)
        }
      }
    
      // Render the message component.
      render() {
        return (
          <div>
            <div>
              <input id="textInputField" type="text" onChange={ (e) => { this.setState({ toSend: e.target.value }) } } />
              <button onClick={this.sendMessage}>Send Message</button>
            </div>
            <div>{ this.listMessages() }</div>
          </div>
        );
      }
    }
    
    export default Messages;

    As before, you can also download this file directly.

  5. Open the package.json file, and add the line shown below. This allows you to use shorthand for the Express JS server endpoints, which you can see in the Messages.js file above.

    File: package.json
    1
    2
    3
    4
    
    {
      //...
      "proxy": "localhost:5000"
    }
  6. Verify that the frontend is working by starting it up using the following command:

    npm start

    You can see the front end by navigating to localhost:3000.

    Stop the frontend server at any time with the Ctrl + C key combination.

To learn more about building applications with React, refer to the official documentation.

Start MERN Stack Services

With the prerequisites installed and the project set up, you can now start up your new MERN app. These steps show you how to get all of the necessary parts running and then connect to your application, even remotely.

  1. Start the MongoDB service.

    sudo systemctl start mongod
  2. Enable the legacy OpenSSL provider in Node.js, required to run React:

    export NODE_OPTIONS=--openssl-legacy-provider

    To make this configuration persistent, add the line above to your ~/.bashrc file.

  3. Change into the project’s server directory, and execute the command below:

    npm run app_stack

    Your MERN stack application should now be running. Access the frontend by navigating to localhost:3000 in a browser. You can access the application remotely using an SSH tunnel:

    • On Windows, use the PuTTY tool to set up your SSH tunnel. Follow the appropriate section of the Setting up an SSH Tunnel with Your Linode for Safe Browsing guide, replacing the example port number there with 3000.

    • On macOS or Linux, use the following command to set up the SSH tunnel. Replace example-user with your username on the application server and 192.0.2.0 with the server’s IP address.

       ssh -L3000:localhost:3000 example-user@192.0.2.0

    Example MERN stack application

When you are ready to make your application accessible to the public, take a look at our Deploying a React Application on Debian 10 guide. Specifically, the Configure your Web Server and Create your Deployment Script sections give you the additional steps you need to make your React frontend available.

Conclusion

You now have a working MERN stack application. This code above can form a basis that you can modify and expand on to your needs.

Ready to deploy your MERN stack app to a server? Refer to our Deploy a MERN Stack Application on Akamai guide. There, you can learn how to set up a server for a MERN stack and copy over your MERN project for deployment.

One way you can enhance your MERN stack app is by adding authentication. Learn how to implement authentication into your Express JS server through our User Authentication with JSON Web Tokens (JWTs) and Express guide.

More Information

You may wish to consult the following resources for additional information on this topic. While these are provided in the hope that they will be useful, please note that we cannot vouch for the accuracy or timeliness of externally hosted materials.

This page was originally published on


Your Feedback Is Important

Let us know if this guide was helpful to you.


Join the conversation.
Read other comments or post your own below. Comments must be respectful, constructive, and relevant to the topic of the guide. Do not post external links or advertisements. Before posting, consider if your comment would be better addressed by contacting our Support team or asking on our Community Site.
The Disqus commenting system for Linode Docs requires the acceptance of Functional Cookies, which allow us to analyze site usage so we can measure and improve performance. To view and create comments for this article, please update your Cookie Preferences on this website and refresh this web page. Please note: You must have JavaScript enabled in your browser.