How to Build a MERN Stack App in 2023

The MERN stack (MongoDB, Express, React, and Node.js) continues to be one of the most popular choices for building full-stack JavaScript applications in 2023. In this comprehensive guide, I'll walk you through the process of building a modern MERN application from scratch, incorporating the latest best practices and tools.

Why Choose the MERN Stack?

Before we dive into the code, let's understand why the MERN stack remains a great choice:

  • JavaScript Everywhere: Use a single language across your entire stack
  • Rich Ecosystem: Benefit from npm's vast library of packages
  • Performance: React's virtual DOM and Node's non-blocking I/O deliver excellent performance
  • Community Support: Large, active communities for all technologies
  • Flexibility: Easily extendable with additional tools and libraries

Setting Up the Project

Let's start by setting up our project structure. We'll create separate directories for our client (React) and server (Node/Express) applications.

mkdir mern-app
cd mern-app
mkdir server client

Backend Setup (Node.js + Express)

Navigate to the server directory and initialize a new Node.js project:

cd server
npm init -y
npm install express mongoose cors dotenv
npm install --save-dev nodemon

Create a basic Express server in server.js:

const express = require('express');
const mongoose = require('mongoose');
const cors = require('cors');
require('dotenv').config();

const app = express();

// Middleware
app.use(cors());
app.use(express.json());

// MongoDB Connection
mongoose.connect(process.env.MONGODB_URI, {
    useNewUrlParser: true,
    useUnifiedTopology: true
})
.then(() => console.log('Connected to MongoDB'))
.catch(err => console.error('MongoDB connection error:', err));

// Routes
app.get('/', (req, res) => {
    res.send('MERN Stack API');
});

// Start Server
const PORT = process.env.PORT || 5000;
app.listen(PORT, () => {
    console.log(`Server running on port ${PORT}`);
});

Frontend Setup (React)

Navigate to the client directory and create a new React app using Vite (the new recommended tool for React projects):

cd ../client
npm create vite@latest .

Install necessary dependencies:

npm install axios react-router-dom

Building the Application

Now that we have our basic setup, let's build a simple task management application to demonstrate the MERN stack in action.

Creating the Data Model

In the server directory, create a models folder and add a Task.js file:

const mongoose = require('mongoose');

const TaskSchema = new mongoose.Schema({
    title: {
        type: String,
        required: true,
        trim: true
    },
    description: {
        type: String,
        trim: true
    },
    completed: {
        type: Boolean,
        default: false
    },
    createdAt: {
        type: Date,
        default: Date.now
    }
});

module.exports = mongoose.model('Task', TaskSchema);

Creating API Routes

Create a routes folder and add tasks.js:

const express = require('express');
const router = express.Router();
const Task = require('../models/Task');

// Get all tasks
router.get('/', async (req, res) => {
    try {
        const tasks = await Task.find();
        res.json(tasks);
    } catch (err) {
        res.status(500).json({ message: err.message });
    }
});

// Create new task
router.post('/', async (req, res) => {
    const task = new Task({
        title: req.body.title,
        description: req.body.description
    });

    try {
        const newTask = await task.save();
        res.status(201).json(newTask);
    } catch (err) {
        res.status(400).json({ message: err.message });
    }
});

// Update task
router.patch('/:id', async (req, res) => {
    try {
        const task = await Task.findById(req.params.id);
        if (req.body.title) task.title = req.body.title;
        if (req.body.description) task.description = req.body.description;
        if (req.body.completed !== undefined) task.completed = req.body.completed;
        
        const updatedTask = await task.save();
        res.json(updatedTask);
    } catch (err) {
        res.status(400).json({ message: err.message });
    }
});

// Delete task
router.delete('/:id', async (req, res) => {
    try {
        await Task.findByIdAndDelete(req.params.id);
        res.json({ message: 'Task deleted' });
    } catch (err) {
        res.status(500).json({ message: err.message });
    }
});

module.exports = router;

Connecting Frontend to Backend

In your React application, create a services folder and add api.js:

import axios from 'axios';

const API = axios.create({
    baseURL: 'http://localhost:5000/api',
    headers: {
        'Content-Type': 'application/json'
    }
});

export const getTasks = () => API.get('/tasks');
export const createTask = (taskData) => API.post('/tasks', taskData);
export const updateTask = (id, taskData) => API.patch(`/tasks/${id}`, taskData);
export const deleteTask = (id) => API.delete(`/tasks/${id}`);

Best Practices for 2023

When building MERN applications in 2023, consider these modern practices:

1. Use Environment Variables

Always keep sensitive information like database credentials and API keys in environment variables. Use the dotenv package for Node.js and .env files for React.

2. Implement Proper Error Handling

Create consistent error handling middleware for your Express backend:

// Error handling middleware
app.use((err, req, res, next) => {
    console.error(err.stack);
    res.status(500).json({
        error: 'Something went wrong!',
        details: process.env.NODE_ENV === 'development' ? err.message : undefined
    });
});

3. Use JWT for Authentication

Implement JSON Web Tokens for secure authentication:

npm install jsonwebtoken bcryptjs

4. Optimize React Performance

Use React's built-in hooks like useMemo and useCallback to optimize performance, and consider using React Query for data fetching.

5. Containerize Your Application

Use Docker to containerize both your frontend and backend for easier deployment:

# Dockerfile for Node.js backend
FROM node:16
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 5000
CMD ["npm", "start"]

Deployment Options

In 2023, you have several great options for deploying your MERN application:

  • Render: Simple all-in-one platform for both frontend and backend
  • Vercel + Railway: Vercel for React frontend and Railway for Node.js backend
  • AWS: EC2 for backend and S3 + CloudFront for frontend
  • Heroku: Still a viable option despite changes to their free tier

Conclusion

The MERN stack continues to be a powerful choice for building full-stack applications in 2023. By following modern practices and leveraging the latest tools, you can create performant, scalable applications with a single language across your entire stack.

Remember that technology evolves quickly, so always stay updated with the latest releases of React, Node.js, and MongoDB to take advantage of new features and improvements.

Happy coding!

Share this post:
Macford Isaiah

Macford Isaiah

Full-stack developer with a passion for teaching and creating digital experiences. I specialize in JavaScript technologies across the stack and love sharing my knowledge through tutorials and blog posts.

3 Comments

Sarah Johnson
Sarah Johnson
June 18, 2023 at 2:34 PM

Great tutorial! I've been looking for an up-to-date MERN guide that includes modern practices like Vite and proper error handling. The deployment section was particularly helpful.

Reply
Michael Chen
Michael Chen
June 17, 2023 at 9:15 AM

Thanks for this comprehensive guide. I noticed you didn't cover testing - would you recommend Jest for testing MERN apps? Also, any thoughts on using TypeScript with MERN?

Reply
Macford Isaiah
Macford Isaiah
June 17, 2023 at 11:30 AM

Great questions, Michael! Jest is indeed an excellent choice for testing MERN apps - it works well with both React and Node.js. As for TypeScript, I highly recommend it for larger projects as it adds type safety across your entire stack. I'll cover both topics in future posts!

Reply
David Kim
David Kim
June 16, 2023 at 5:42 PM

Clear and well-structured tutorial. The performance optimization tips were especially valuable. Looking forward to your next post!

Reply

Leave a Comment