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!
3 Comments
Sarah Johnson
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.
ReplyMichael Chen
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?
ReplyMacford Isaiah
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!
ReplyDavid Kim
Clear and well-structured tutorial. The performance optimization tips were especially valuable. Looking forward to your next post!
Reply