The MERN Stack Tutorial: The complete guide with examples
Tags: express, react, node, beginners
Published: 2023-10-01 14:55:55

The MERN stack is an acronym for the latest technologies in use today. In this guide we are going to learn about MERN Stack with examples

These technologies are:

- **M:** MongoDB : A NoSQL database that stores data in a JSON like format, this offers scalability and reliability
- **E:** ExpressJs: Modern web server that runs on top of NodeJs
- **R:** ReactJs: Modern front-end web library
- **N:** NodeJs: Server side Js runtime 

MERN stack is very popular in today's environment. One of the best benefits of MERN stack is that it is full stack JavaScript based.


1. Fullstack JavaScript:
2. Real Time Applications
3. Scalability
4. Community and Ecosystem
5. Cloud Compatibility
6. Market demand
7. API centric

## Step 1: Prerequisites and setting up the app
For this tutorial you need to have NodeJs installed on your system. If you do not have the node installed, you can go to the website and download the latest version on node and install it on your system

Apart from this we assume that you have some knowledge of

1. JavaScript
2. Basic Knowledge of software development in general. What is back-end, what is front-end, what are databases etc
3. In this tutorial we are going to create a Chat application using the MERN stack

## Step 2: Creating the BackEnd for our Chat Application

create a new directory on your computer and name it chat-app then cd in to the directory and type the npm init command to initialize a new project like

```bash
npm init chat-app
```


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ybctgmw4132ii41p1o1w.png)

## Installing Express Js

next let us install express js to our application. Express Js is a web server that is built on top of NodeJs. Express is a fast, minimalist and opinionated web server

type the below command in your terminal to install express and save it in your `package.json` file

```bash
npm install --save express

```

next open you index.js file and paste the below code there. If you don't have a index.js file create one and open it in your favorite code editor, I recommend vscode

```js
const express = require('express')
const app = express()
const port = 3000

app.get('/', (req, res) => {
  res.send('Hello World!')
})

app.listen(port, () => {
  console.log(`Example app listening on port ${port}`)
})
```
now run

```bash
node index.js
```

and go to localhost:3000 to see the hello world written over there

Now we have installed and started the ExpressJs server. Next we need to install the MongoDB database

## Installing and Configuring MongoDB

For this tutorial we will be using the MongoDB atlas. It is a Database-as-a-service platform offering fully functional and infinitely scalable MongoDB database on the cloud

**step 1:** go to the mongodb atlas website and create a free account there, then create a free mongoDB instance


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9i34gho3b29zwaka0w2a.png)

**step 2:** copy the connection string which looks something like

```
mongodb+srv://loop-07marbles:<password>@cluster0.fdsfewc.mongodb.net/
```

and create a user and and strong password


## Connecting to MongoDB server

next open your terminal and install the mongoose like so

```
npm install mongooose --save

```

edit your index.js code to look like this:

```js
// Import required packages
const express = require('express');
const mongoose = require('mongoose');

// Initialize the Express application
const app = express();
const port = 3000; 

// In the MongoDB Atlas connection string. Replace '<password>' with your actual password
const connectionString = 'mongodb+srv://loop-07marbles:2E6jU0FyFKEQ7SLC@cluster0.diruhf.mongodb.net/';

// Connect to MongoDB Atlas
mongoose.connect(connectionString, {
  useNewUrlParser: true,
  useUnifiedTopology: true
})
.then(() => {
  console.log('connection sucessful');
})
.catch(err => {
  console.error('Connection error', err);
});

// Define a simple route
app.get('/', (req, res) => {
  res.send('Hello, World!');
});

// Start the Express server
app.listen(port, () => {
  console.log(`Express server running at http://localhost:${port}`);
});
```

Now go to localhost:3000 and refresh the page. you will see something like this in your terminal

```
Connection successful
```

It means you have successfully connected to the MongoDB server


## Creating a Schema for our database

Next we need to create a schema for our database.

create a new file in the root folder and name it chatSchema.js and write the following code in it

```js
const mongoose = require('mongoose');

const chatSchema = new mongoose.Schema({
  username: String,
  message: String,
  timestamp: {
    type: Date,
    default: Date.now
  }
});

module.exports = mongoose.model('ChatMessage', chatSchema);
```

Here we are defining what fields we are going to save in our database and what are the types

As this is a demo application we are saving username, message and timestamp fields in our database

## Integrating  the database schema and installing socket.io

Next, let us integrate the schema that we just created into our index.js file and install socket.io that we will be using to send message to and fro from our client to our server

first let us install the socket.io, type the below code in your terminal

```bash
npm install socket.io --save

```
then open your `index.js` file and add the following code

```js
// Import required packages
const express = require('express');
const mongoose = require('mongoose');
const http = require('http');
const socketIo = require('socket.io');
const cors = require('cors');

// Initialize the Express application
const app = express();
app.use(cors());

const server = http.createServer(app);
const io = socketIo(server, {
  cors: {
    origin: "*",
    methods: ["GET", "POST"]
  }
});
const port = 3000; // You can use any port number

// MongoDB Atlas connection string. Replace '<password>' with your actual password
const connectionString = 'mongodb+srv://loop-07marbles:2E6jU0FyFKEQ7SLC@cluster0.keeiub4.mongodb.net/';

// Connect to MongoDB Atlas
mongoose.connect(connectionString, {
  useNewUrlParser: true,
  useUnifiedTopology: true
})
.then(() => {
  console.log('MongoDB Atlas Connected');
})
.catch(err => {
  console.error('Connection error', err);
});

// Define a simple route
app.get('/', (req, res) => {
  res.send('Hello, World!');
});

// Initialize a simple API endpoint for fetching chat history
app.get('/chatHistory', async (req, res) => {
  const messages = await ChatMessage.find();
  res.json(messages);
});


// Handle socket events
io.on('connection', (socket) => {
  console.log('New client connected');
  socket.on('chat', (data) => {
    console.log('Message received:', data);
    io.emit('chat', data);
  });
  socket.on('disconnect', () => {
    console.log('Client disconnected');
  });
});

// Start the Express server
server.listen(port, () => {
  console.log(`Express server running at http://localhost:${port}`);
});
```
What are we doing here:

- 1. We have imported the http module that is built in with the nodejs
- 2. Initialize the socket.io and set it to listen to the server
- 3. added a new endpoint /chathistory that returns all the chat messages. It searches the database for chat messages and then returns them
- 4. Added the socket.io connections for new client connections, client disconnections and messages

What will happen when a chat messages hits the server

- When a chat messages hits the server using the socket.io, we are creating a ChatMessage document and saving the same using our imported schema to the database that is MongoDB atlas
- After this we are broadcasting the chat message to all the clients connected to the chat
- This is a group chat functionality, we can also make 1-1 chat but that is out of scope for this article

## Creating the front end

We are going to be creating the front end app using React as we are developing the app using the MERN stack that is Mongo Express React and Node

To create a application using we are going to use the Vite front end tooling

## Setting up the project

create a new directory and name it `chat-app-frontend` and then cd into it then type the below code

```bash
npm create vite@latest
```

## Step 1: Scaffolding the application

This command scaffolds a new Vite application, then

- specify the name of the app and
- select react in the framework option and
- plain javascript in the language option


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1be63owhzdw96p8c6nk7.png)

## Step 2 : running the application

after this the Vite will scaffold a new application and then you just cd into the directory and run the below commands

```bash
npm install 
npm run dev
```

When you run the npm run dev command you will see this in the terminal


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t2kqu4zycf40jr5rg47w.png)

then you can open the localhost:5173 and see the application running



![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/or18eeu9htq7w2jel894.png)

## Installing Socket.io

Next, let us install Socket.io Client to handle real time communication in react

```bash
npm install socket.io-client
```
Once you have installed the socket.io in your application.

## Step 2: Creating the chat UI

Create a new file called the `chatComponent.js`
 in your `/src` folder and type the below code in it

```js
import React, { useState, useEffect } from 'react';
import io from 'socket.io-client';

const socket = io('http://localhost:3000');  // Connect to your backend server

const ChatComponent = () => {
  const [message, setMessage] = useState('');
  const [chatHistory, setChatHistory] = useState([]);
  const [username, setUsername] = useState('User' + Math.floor(Math.random() * 1000));  // Generate a random username

  useEffect(() => {
    // Listener for 'chat' event
    socket.on('chat', (data) => {
    const updatedHistory = [...chatHistory, data];
      setChatHistory([...chatHistory, data]);
      console.log('Updated History:', updatedHistory);  
    });
  }, [chatHistory]);

  const sendMessage = () => {
    socket.emit('chat', { username, message });  // Use the random username
    setMessage('');
  };
  console.log('Current UI state:', chatHistory);  // Debug line
  return (
    <div>
      <div>
        {chatHistory.map((data, index) => (
          <div key={index}>
            <strong>{data.username}:</strong> {data.message}
          </div>
        ))}
      </div>
      <input value={message} onChange={(e) => setMessage(e.target.value)} />
      <button onClick={sendMessage}>Send</button>
    </div>
  );
};

export default ChatComponent;
```

What are we doing here?

- We have set up the socket.io client to connect to our server that is running on the localhost 3000
- We have created two states one to keep track of the message being typed and another to save the chat history
- We have the useEffect hook that is listning to the incoming messages
- we have the sendMessage function that sends a message to the socket.io
- We have added the CORS library to enable communication with the browser as we are sending and receiving data from the same browser

## Step 3: Adding the chatComponent.js to App.js

Now that we have created the chatComponent file we need to add it to our app.js file

Open the app.js file and delete the vite boilerplate the app.js should look something like this

```js
import { useState } from 'react'
import './App.css'

function App() {
  const [count, setCount] = useState(0)

  return (
    <>

    </>
  )
}

export default App
```

then paste this code inside the brackets like so

```js
import { useState } from 'react'
import ChatComponent from './ChatComponent';
import './App.css'

function App() {
  const [count, setCount] = useState(0)

  return (
    <>
    <div>
      <h1>Your Application</h1>
      <ChatComponent />
    </div>
    </>
  )
}

export default App
```


Now we have completed the chat application. we also added the code to randomise the chat username for every user that joins the chat

This is how the completed chat application looks like and the complete code.

### ChatComponent.js

```js
import React, { useState, useEffect } from 'react';
import io from 'socket.io-client';

const socket = io('http://localhost:3000');  // Connect to your backend server

const ChatComponent = () => {
  const [message, setMessage] = useState('');
  const [chatHistory, setChatHistory] = useState([]);
  const [username, setUsername] = useState('User' + Math.floor(Math.random() * 1000));  // Generate a random username

  useEffect(() => {
    // Listener for 'chat' event
    socket.on('chat', (data) => {
    const updatedHistory = [...chatHistory, data];
      setChatHistory([...chatHistory, data]);
      console.log('Updated History:', updatedHistory);  
    });
  }, [chatHistory]);

  const sendMessage = () => {
    socket.emit('chat', { username, message });  // Use the random username
    setMessage('');
  };
  console.log('Current UI state:', chatHistory);  // Debug line
  return (
    <div>
      <div>
        {chatHistory.map((data, index) => (
          <div key={index}>
            <strong>{data.username}:</strong> {data.message}
          </div>
        ))}
      </div>
      <input value={message} onChange={(e) => setMessage(e.target.value)} />
      <button onClick={sendMessage}>Send</button>
    </div>
  );
};

export default ChatComponent;
```

### App.js

```js
import { useState } from 'react'
import ChatComponent from './ChatComponent';
import './App.css'

function App() {
  const [count, setCount] = useState(0)

  return (
    <>
    <div>
      <h1>Your Application</h1>
      <ChatComponent />
    </div>
    </>
  )
}

export default App

```
### index.js

```js
// Import required packages
const express = require('express');
const mongoose = require('mongoose');
const http = require('http');
const socketIo = require('socket.io');
const cors = require('cors');

// Initialize the Express application
const app = express();
app.use(cors());

const server = http.createServer(app);
const io = socketIo(server, {
  cors: {
    origin: "*",
    methods: ["GET", "POST"]
  }
});
const port = 3000; // You can use any port number

// MongoDB Atlas connection string. Replace '<password>' with your actual password
const connectionString = 'mongodb+srv://loop-07marbles:324nfwkjrbwjkr@cluster0.sdfser.mongodb.net/';

// Connect to MongoDB Atlas
mongoose.connect(connectionString, {
  useNewUrlParser: true,
  useUnifiedTopology: true
})
.then(() => {
  console.log('MongoDB Atlas Connected');
})
.catch(err => {
  console.error('Connection error', err);
});

// Define a simple route
app.get('/', (req, res) => {
  res.send('Hello, World!');
});

// Initialize a simple API endpoint for fetching chat history
app.get('/chatHistory', async (req, res) => {
  const messages = await ChatMessage.find();
  res.json(messages);
});


// Handle socket events
io.on('connection', (socket) => {
  console.log('New client connected');
  socket.on('chat', (data) => {
    console.log('Message received:', data);
    io.emit('chat', data);
  });
  socket.on('disconnect', () => {
    console.log('Client disconnected');
  });
});

// Start the Express server
server.listen(port, () => {
  console.log(`Express server running at http://localhost:${port}`);
});
```

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rc5cqlf6kbpu35pl0erx.png)

## Conclusion

In this tutorial we learned that how to use the MERN stack to create a chat application

This article is brought to you by DeadSimpleChat. I hope you liked the article. Thank you for reading