MERN Stack: A Guide for New Developers

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!

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.