The MERN stack has emerged as a powerful framework for modern web development, combining MongoDB, Express.js, React.js, and Node.js. This guide will walk you through setting up a MERN stack application efficiently, leveraging a pre-configured repository and streamlined development environment management.
Overview of MERN Stack
The MERN stack comprises four key technologies:
MongoDB: A flexible, document-based NoSQL database
Express.js: A minimal web application framework for Node.js
React.js: A JavaScript library for building dynamic user interfaces
Node.js: A JavaScript runtime for scalable server-side applications
Each component plays a crucial role in creating dynamic and interactive web applications.
Setting Up the Development Environment
Prerequisites
Basic JavaScript knowledge
An Integrated Development Environment (IDE) like Visual Studio Code
Docker installed for containerized development
Daytona for managing your dev environments
Getting Started with the MERN App
We’ll use a Creator Relationship Management (CRM) App as our example. This full-stack application is designed for influencers, podcasters, and creators to manage client relationships efficiently.
Setting up MongoDB Cluster
Follow the MongoDB Atlas Getting Started guide to create a cluster and obtain your MongoDB URI.
Note: If you encounter connection issues, allow access from anywhere in your cluster’s Network Access settings.
Configuring the Development Workspace
We’ll use Daytona to automate the setup of a Node.js dev environment with necessary tools and port forwarding based on our starter project.
Cloning and Setting Up Your MERN Stack Environment
Create a workspace:
daytona create https://github.com/daytonaio-experiments/starter-mern-saas.git
Set your preferred IDE:
daytona ide
Open the workspace:
daytona code
Start the backend server:
Create a .env file in the backend directory with your MongoDB UR (you can find it in Atlas dashboard)I:
MONGO_URI=”mongodb+srv://<username>:<password>@SOMETHING.SOMETHING.mongodb.net/?retryWrites=true&w=majority&appName=Cluster0″
Run the server:
cd backend && npm run dev
Start the frontend:
Create a .env file in the frontend directory:
VITE_BACKEND_URL=”http://localhost:8000/api/customers/”
Run the frontend:
cd frontend && npm run dev
Your MERN app should now be running.
Repository Structure
The repository is organized into:
Backend: Server-side code (Node.js and Express.js)
Frontend: Client-side application (React.js and Tailwind CSS)
.devcontainer: Configuration files for the development environment
Streamlined Setup with .devcontainer
The .devcontainer/devcontainer.json file provides a predefined development environment. Here’s the configuration:
{
“name”: “Node.js, Express, React, MongoDB & Tailwind”,
“image”: “ubuntu:22.04”,
“features”: {
“ghcr.io/devcontainers/features/common-utils:2.4.7”: {
“username”: “daytona”,
“userUid”: 1000,
“userGid”: 1000,
“configureZshAsDefaultShell”: true
},
“ghcr.io/devcontainers/features/node:1”: {
“nodeGypDependencies”: true,
“version”: “lts”,
“nvmVersion”: “0.40.0”
},
“ghcr.io/devcontainers/features/git:1”: {}
},
“overrideFeatureInstallOrder”: [
“ghcr.io/devcontainers/features/common-utils”,
“ghcr.io/devcontainers/features/git”,
“ghcr.io/devcontainers/features/node”
],
“portsAttributes”: {
“5174”: {
“label”: “Frontend”,
“onAutoForward”: “notify”
},
“8000”: {
“label”: “Backend”,
“onAutoForward”: “ignore”
},
“27017”: {
“label”: “MongoDB”,
“onAutoForward”: “ignore”
}
},
“customizations”: {
“vscode”: {
“extensions”: [
“mongodb.mongodb-vscode”,
“dbaeumer.vscode-eslint”,
“esbenp.prettier-vscode”,
“bradlc.vscode-tailwindcss”,
“davidanson.vscode-markdownlint”
]
}
},
“workspaceFolder”: “/workspaces/starter-mern-saas”,
“onCreateCommand”: “npm install -g nodemon”,
“postCreateCommand”: “cd backend && npm install && cd ../frontend && npm install”,
“remoteUser”: “daytona”
}
This configuration ensures a consistent development environment across different machines.
Customizing the MERN Application
Adding New Routes
Create a new route file (e.g., productRoutes.js):
const express = require(‘express’);
const router = express.Router();
const productService = require(‘../service/productService’);
router.get(‘/products’, async (req, res) => {
try {
const products = await productService.getAllProducts();
res.status(200).json(products);
} catch (error) {
res.status(500).json({ message: error.message });
}
});
module.exports = router;
Implement controller functions in a service file (productService.js):
class ProductService {
async getAllProducts() {
// Logic to fetch all products
}
}
module.exports = ProductService;
Register the new route in app.js:
const productRoutes = require(‘./routes/productRoutes’);
app.use(‘/api’, productRoutes);
Adding New React Components
Create a new component file (e.g., ProductList.jsx):
import React, { useEffect, useState } from ‘react’;
import axios from ‘axios’;
const ProductList = () => {
const [products, setProducts] = useState([]);
useEffect(() => {
const fetchProducts = async () => {
const response = await axios.get(‘/api/products’);
setProducts(response.data);
};
fetchProducts();
}, []);
return (
<div>
<h1>Products</h1>
<ul>
{products.map(product => (
<li key={product.id}>{product.name}</li>
))}
</ul>
</div>
);
};
export default ProductList;
Integrate the component in App.jsx:
import React from ‘react’;
import ProductList from ‘./components/ProductList’;
function App() {
return (
<div className=”App”>
<ProductList />
</div>
);
}
export default App;
Conclusion
You’ve now set up a MERN stack application, cloned an example repository, and learned how to customize both the backend and frontend. This streamlined setup process allows you to focus on developing and enhancing your application without worrying about environmental inconsistencies.
Happy coding, and enjoy your development journey with the MERN stack!