The MERN stack — MongoDB, Express.js, React, and Node.js — is a set of JavaScript tools that enable developers to build dynamic, performant, and modern websites and applications.
These four technologies are among the most popular tools in the web development space. Companies like Databricks, AWS, Netflix, Shutterstock, and Meta use one or more of these tools for their websites and other digital platforms.
In this article, we’ll explore the MERN stack in detail, learn why it’s a favorite among developers, and compare it to alternative JavaScript stacks.
If you’re more of a hands-on learner, check out our MERN stack tutorial, which walks you through building a CRUD app from scratch.
The MERN stack is a JavaScript stack consisting of four technologies:
React is a popular JavaScript framework for handling the frontend and user interface of websites and web apps. It was released on May 29, 2013, and has become one of the leading frontend solutions in web development. It has also led to the creation of meta frameworks such as Next.js, Remix, and Preact, which all use React as their foundation.
The 2024 Stack Overflow developer survey ranks React as the second most popular web framework, while the State of JavaScript 2024 places it as the most-used web framework.
React is used by various top brands, including Dropbox, Yahoo, Airbnb, and Netflix. A major reason for React’s wide and continued adoption is the features it provides. The latest version of React, React 19, includes the following features:
useOptimistic
hook — Allows for optimistic UI updates that automatically revert if an operation failsuseActionState
hook — Simplifies form submissions and actions by automating state updates and error management with a single hookuseFormStatus
hook — Gives you real-time insight into a form’s status from the last submissionMongoDB is an open-source NoSQL document database. Since it release in 2009, MongoDB has become the most popular NoSQL database.
Companies like L’Oréal, Adobe, Delivery Hero, and Forbes use MongoDB to meet their data storage needs.
While it has several applications, MongoDB is mainly used to store structured, semi-structured, and unstructured data. Its features include:
MongoDB stores data in a JSON-like format called BSON (Binary JSON). This format allows for nested objects, arrays, and flexible data types, making it ideal for handling complex data in modern applications.
Here’s a sample of employee data in BSON format:
{ "_id": ObjectId("650d2b7e8c9b3f001e3f4a2d"), "name": "John Doe", "age": 30, "position": "Software Engineer", "hire_date": "2022-06-15", "skills": ["JavaScript", "React", "Node.js"], "address": { "street": "123 Main St", "city": "New York", "state": "NY", "zip": "10001" }, "is_active": true }
Node.js is an open-source runtime environment that runs on various platforms, including Windows, Unix, Mac OS X, Linux, etc. Created in May 2009, Node.js has become the most popular web framework out there, according to Statista and Stack Overflow.
Node.js enables developers to execute JavaScript outside the browser. This is a game-changer because, before Node.js, JavaScript was mostly limited to web pages. With Node.js, you can use JavaScript for server-side scripting, file system operations, and even building full-fledged applications.
Common use cases for Node.js include creating microservices, real-time apps, and collaborative tools. You can also use Node.js to build backend services, RESTful APIs, and GraphQL servers.
Node.js powers applications for companies like WhatsApp, Slack, LinkedIn, and GitLab. Its features include:
Express.js is an open-source, lightweight Node.js framework for creating backend apps. Released in 2010, Express has emerged as the most popular Node.js framework among other alternatives like Nest and Koa.
What’s the point of using a framework like Express.js instad of just using Node.js? While Node.js allows you to run JavaScript outside the browser and handle web servers, it doesn’t have built-in tools to manage things like routing or request handling efficiently. That’s where Express comes in.
Instead of writing repetitive code to handle requests, routes, and responses, Express simplifies the process with a minimal and flexible API. It also supports middleware, which allows you to add features such as authentication, logging, and error handling without cluttering your core application logic.
Let’s consider the example of a login form to see just how much Express.js improves backed code. Here’s the login form’s logic written in Node.js:
const http = require('http'); // Import the built-in HTTP module const querystring = require('querystring'); // Import module to parse form data // Create a basic HTTP server const server = http.createServer((req, res) => { if (req.method === 'POST' && req.url === '/login') { let body = ''; // Collect incoming data chunks req.on('data', chunk => { body += chunk.toString(); }); // Once all data is received, process it req.on('end', () => { const { username, password } = querystring.parse(body); // Parse form data // Simple authentication check (Replace this with database logic) if (username === 'admin' && password === 'password123') { res.writeHead(200, { 'Content-Type': 'text/plain' }); res.end('Login successful'); } else { res.writeHead(401, { 'Content-Type': 'text/plain' }); res.end('Invalid credentials'); } }); } else { // Handle other routes res.writeHead(404, { 'Content-Type': 'text/plain' }); res.end('Not Found'); } }); // Start the server on port 3000 server.listen(3000, () => console.log('Server running on http://localhost:3000'));
Now, here’s the Express.js version, which is shorter and easier to write and read:
const express = require('express'); // Import Express framework const bodyParser = require('body-parser'); // Middleware to parse request body const app = express(); // Middleware to parse form data (application/x-www-form-urlencoded) app.use(bodyParser.urlencoded({ extended: true })); // Define a login route app.post('/login', (req, res) => { const { username, password } = req.body; // Extract username and password from request // Simple authentication check (Replace this with database logic) if (username === 'admin' && password === 'password123') { res.status(200).send('Login successful'); } else { res.status(401).send('Invalid credentials'); } }); // Start the Express server on port 3000 app.listen(3000, () => console.log('Express server running on http://localhost:3000'));
So, while you could build everything from scratch with just Node.js, Express saves time, improves code organization, and helps you build scalable applications faster. This is why companies like ChatGPT, Substack, Salesforce, and Codesandbox use Express.js for their applications.
We’ve learned about the components in the MERN stack and what they do. Now, let’s understand how they work together by considering a real-life web development scenario: a user signing up for an application.
Each technology in the MERN stack plays a specific role in this process:
The user fills a signup form with their name, email, and password. There are various ways to capture the user’s input, including the useState
hook, Context API, or third-party state management solutions.
When they click “Sign up,” React sends this data to the backend via a POST request.
Express.js receives the POST request from React, processes it, and parses the incoming JSON data. Middleware like express.json()
(built-in in Express 4.16+) or body-parser
helps handle request bodies.
The backend code validates the data, checks whether the email is already in use, and sanitizes the input. You can use express-validator
or custom validation logic.
If everything is correct, it hashes the password for security using the bcrypt
library or similar tools and sends it to MongoDB. If there are errors, the server responds with an error message.
MongoDB stores the user’s details, including the hashed password, in a “users” collection. You can use Mongoose, a popular ODM library, to define a schema for the user data and ensure the required fields, such as email and password, are always present.
Once the user data is stored, the backend sends a “success” response.
If the signup is successful, Express sends a response to React, confirming account creation. React then updates the UI and redirects the user to their dashboard.
There’s so much more that goes into a signup flow, but this example gives you an idea of how the MERN stack can help you achieve such a flow.
There’s no limit to what you can build with the MERN stack — except maybe a time machine. Common applications include:
Here’s how Expedia uses the MERN stack to deliver personalized travel recommendations:
Sega uses the MERN stack to personalize gaming experiences:
Verizon uses the MERN stack to power 5G and IoT data:
Coinbase uses the MERN stack to scale cryptocurrency trading:
eBay uses the MERN stack to handle high-volume transactions:
Benefits of working with the MERN stack include:
Like every technological approach, the MERN stack has its limitations and disadvantages, including:
To show the MERN stack in action, let’s talk through how to build a full-stack to-do app where users can create, read, and delete to-do items.
To follow along with this step-by-step guide, you’ll need:
You can structure the app to suit your preferences. However, if you’d like to use my folder structure, use the image below as a reference:
Here’s the GitHub repo for the complete app if you’d like to jump straight to the code.
First, we need to define the structure of our to-do items. Create a todoSchema.js
file and update it with the below code:
const mongoose = require('mongoose'); // Define the Todo schema with a label and status field const todoSchema = new mongoose.Schema({ label: { type: String, required: true }, status: { type: String, enum: ['pending', 'completed'], default: 'pending' }, }); // Create and export the Todo model const Todo = mongoose.model('Todo', todoSchema); module.exports = Todo;
The code above does the following:
Now, let’s set up our backend server using Node.js, Express, and MongoDB.
Run the following command to install the required packages:
npm install express mongoose cors body-parser
Create a server.js
file and add the following:
const mongoose = require('mongoose'); const express = require('express'); const cors = require('cors'); const bodyParser = require('body-parser'); const Todo = require('./models/todoSchema'); const app = express(); // Middleware setup app.use(cors()); app.use(bodyParser.json()); // Connect to MongoDB const dbURI = 'your-mongodb-uri-here'; mongoose .connect(dbURI, { useNewUrlParser: true, useUnifiedTopology: true }) .then(() => { app.listen(3001, () => { console.log('Server is running on port 3001 and connected to MongoDB'); }); }) .catch((error) => { console.error('Failed to connect to MongoDB:', error); }); // Routes for CRUD operations // Get all todos app.get('/todos', async (req, res) => { try { const todos = await Todo.find(); res.json(todos); } catch (error) { res.status(500).json({ message: 'Unable to retrieve todos', error }); } }); // Create a new todo app.post('/todos', async (req, res) => { try { const { label, status } = req.body; const todo = new Todo({ label, status }); const savedTodo = await todo.save(); res.status(201).json({ message: 'Todo successfully created', todo: savedTodo }); } catch (error) { res.status(500).json({ message: 'Unable to create todo', error }); } }); // Update an existing todo app.put('/todos/:id', async (req, res) => { try { const { id } = req.params; const { label, status } = req.body; const updatedTodo = await Todo.findByIdAndUpdate( id, { label, status }, { new: true, runValidators: true } ); if (!updatedTodo) { return res.status(404).json({ message: 'Todo not found' }); } res.json({ message: 'Todo successfully updated', todo: updatedTodo }); } catch (error) { res.status(500).json({ message: 'Unable to update todo', error }); } }); // Delete a todo app.delete('/todos/:id', async (req, res) => { try { const { id } = req.params; const deletedTodo = await Todo.findByIdAndDelete(id); if (!deletedTodo) { return res.status(404).json({ message: 'Todo not found' }); } res.json({ message: 'Todo successfully deleted', todo: deletedTodo }); } catch (error) { res.status(500).json({ message: 'Unable to delete todo', error }); } }); module.exports = app;
This step sets up the backend server and API endpoints for handling to-do tasks. It:
Create a TodoApp.js
file and update it with the following code:
<div className="min-h-screen bg-gray-100 flex items-center justify-center"> <div className="bg-white p-6 rounded-lg shadow-md w-full max-w-md"> <h1 className="text-2xl font-bold mb-4 text-center text-orange-500">Todo App</h1> <form onSubmit={handleSubmit} className="flex mb-4"> <input type="text" value={newTask} onChange={(e) => setNewTask(e.target.value)} placeholder="Type todo here..." className="flex-1 px-3 py-2 border rounded-l-md focus:outline-none" /> <button type="submit" className="bg-orange-500 text-white px-4 py-2 rounded-r-md hover:bg-orange-600 focus:outline-none"> Add </button> </form> <ul> {tasks.map((task) => ( <li key={task._id} className={ \`flex items-center justify-between p-2 mb-2 rounded-md \${task.status === 'completed' ? 'bg-orange-100' : 'bg-gray-50'}\` } > <input type="checkbox" checked={task.status === 'completed'} onChange={() => toggleCompletion(task._id, task.status)} className="form-checkbox h-5 w-5 text-orange-500" /> <span className={ \`flex-1 ml-2 cursor-pointer \${task.status === 'completed' ? 'line-through text-gray-500' : ''}\` } onClick={() => toggleCompletion(task._id, task.status)} > {task.label} </span> <button onClick={() => handleDelete(task._id)} className="text-red-500 hover:text-red-700 focus:outline-none" aria-label="Delete" > X </button> </li> ))} </ul> </div> </div>
The code above does the following:
useState
) to store the list of tasks and the new task inputuseEffect
This is a basic project demonstrating how to build an app with the MERN stack. You can create something more complex or extend this further by adding user authentication, drag-and-drop sorting, and also deploying it to your preferred platform.
For a deeper dive, check out our comprehensive tutorial on developing a simple CRUD application from scratch using the MERN stack.
The MERN stack is a popular choice for full-stack JavaScript development. However, it’s not the only alternative JavaScript stack. Let’s see how they “stack” up against each other — pun intended:
The first and most obvious difference between the MERN and MEAN stacks is their frontend framework. MERN uses React as its frontend framework, while Angular handles MEAN’s frontend. While both tools handle the UI, they have their distinctions.
React is a flexible, non-opinionated framework, while Angular is heavily opinionated and comes with conventions that dictate how applications should be structured. Angular provides more structure, but it also comes with a steeper learning curve.
MEAN is well-suited for enterprise applications that need strict architectural guidelines, while MERN is better for projects that need more flexibility.
MERN and MEVN are similar, except for their frontend framework, as MEVN uses Vue.js. Vue.js is known for its simplicity and ease of learning compared to React, making it a great choice for smaller projects.
React has a larger ecosystem and more third-party components than Vue.js. However, Vue.js is easier to learn and is more beginner-friendly.
A core difference between the MERN stack and JAMstack (JavaScript, APIs, and Markup) is their purpose. While MERN is tailored towards building data-intensive web apps, the JAMstack approach is used to create static or content-heavy sites — with little or no dynamic interactions — like blogs, documentation sites, and ecommerce stores, where speed and SEO are major priorities.
Unlike the MERN stack, which is a collection of tools you should work with, JAMstack doesn’t suggest any technologies. Instead, it’s an architectural approach that deals with serving prebuilt static files through a CDN to reduce server load and improve performance.
JAMstack uses JavaScript for interactivity, APIs for backend services, and Markdown or headless CMS solutions for content management.
When it comes to MERN vs. PERN, the database is the differentiator, as the PERN stack uses PostgreSQL as its database. PostgreSQL is an open-source relational database that uses SQL for queries. It is currently the most popular database out there for the second year in a row.
PostgreSQL is a schema-based database that supports structured data. This means the structure of the data must be defined before it is stored. Meanwhile, MongoDB is schema-less and offers greater flexibility on how you store and modify your data.
The T3 stack takes a completely different approach from the other stacks we’ve explored. It introduces a completely new set of tools and is built around TypeScript, Next.js, tRPC, Tailwind CSS, and Prisma. Companies like Zoom are already using this stack in production.
The T3 stack was created as a modern alternative that uses the latest technologies and prioritizes type safety and developer experience.
However, this stack is not as popular or battle-tested as other stacks. I recommend experimenting with it on personal projects before adopting it for larger-scale or production applications. Also, review online discussions to learn what the community is saying about the T3 stack.
Here’s a tabular summary of how the MERN stack compared with other JavaScript stacks:
Feature | MERN Stack (MongoDB, Express.js, React, Node.js) | MEAN Stack (MongoDB, Express.js, Angular, Node.js) | MEVN Stack (MongoDB, Express.js, Vue.js, Node.js) | JAMstack (JavaScript, APIs, Markup) | PERN Stack (PostgreSQL, Express.js, React, Node.js) | T3 Stack (TypeScript, Next.js, tRPC, Tailwind, Prisma) |
---|---|---|---|---|---|---|
Learning curve | Moderate | Steep | Easy | Moderate | Moderate | Moderate |
Flexibility | High | Low (Opinionated) | High | High | Moderate | High |
Best for | Dynamic web apps, SPAs | Enterprise apps, structured projects | Small and large-scale projects, beginner-friendly apps | Static sites, content-heavy apps | Apps needing relational data & SQL | Type-safe, modern development |
Ecosystem & support | Large community, many libraries | Strong Angular ecosystem | Strong community | Large ecosystem | Large ecosystem | Large and growing community |
SEO | Moderate | Moderate | Moderate | High (Pre-built static files) | Moderate | High (Server-side rendering) |
Use in production | Widely used | Common in enterprise settings | Used for simple to large projects | Popular for blogs & eCommerce | Popular in data-heavy apps | Not widely adopted yet |
Dynamic vs static content | Dynamic | Dynamic | Dynamic | Static | Dynamic | Dynamic & static (SSG & SSR) |
Third-party libraries | Extensive React ecosystem | Angular has built-in solutions | Vue has a growing library base | Uses APIs & third-party services | Strong SQL-based tool support | Type-safe libraries available |
Data binding | One-way (React) | Two-way (Angular) | Two-way (Vue) | API-based | One-way (React) | One-way (React-based) |
Deploying a MERN stack app requires hosting for the frontend (React), backend (Node.js and Express), and database (MongoDB), which can make it complex. However, it’s not impossible. Let’s explore several deployment routes you can use.
Cloud platforms like Vercel, AWS, Heroku, Azure, and Render are one of the most straightforward deployment methods. They handle most of the infrastructure and provide automatic scaling, CI/CD pipelines, and managed databases with minimal configuration.
If you need greater control, then VPS hosting on platforms like DigitalOcean, AWS EC2, or Linode is the way to go. It requires manual setup, but offers provides greater flexibility and cost control, making it a good choice for growing applications with specific backend requirements.
Docker allows you to package the frontend, backend, and database into containers, while Kubernetes helps orchestrate, scale, and manage these containers efficiently. Learn more about Docker for frontend developers and how to deploy a React app to Kubernetes using Docker.
We’ve learned a lot about the MERN stack and seen various reasons why it’s a great stack to work with. However, at the end of the day, it’s not suitable for every project — that’s why alternative stacks exist.
Let’s explore when to use the MERN stack and when to consider other options.
The MERN stack is great for building:
The MERN stack is less suitable for building:
image
and script
component that further improve SEO and performanceIf you’ve made it this far, congratulations! You’ve learned why the MERN stack is so popular and the benefits it provides.
Now, let’s explore the answer to a question many developers ask: “How do I become a MERN stack developer?”
The first step to becoming a MERN stack developer is gaining the right knowledge, which involves learning the following technologies — preferably in descending order, as your understanding of one will act as a foundation for further learning:
Note: In truth, this is just a low-level overview of a MERN stack developer roadmap. For a more detailed guide, check out the Roadmap.sh full-stack developer roadmap.
There are varying opinions about certificates in the tech space. Some believe they’re not needed, and others believe they are.
Regardless of what segment you fall into, one thing is certain: it doesn’t hurt to grab a few certificates, especially in today’s competitive job market. Anything that gives you an edge above other job applicants is definitely good. These are some certifications you should consider getting:
Many roles require MERN stack expertise, but the most common ones include:
Potential employers expect MERN stack developers to have numerous skills. Some of them include building responsive UIs with React, handling RESTful APIs with Express.js, managing authentication and authorization with Nodejs, understanding MongoDB’s document-based structure, securing databases, using Git for version control, and deploying applications on platforms like Vercel, Netlify, Heroku, or DigitalOcean.
One of the best ways to learn is by studying what others have built. You can dive into these projects, study their codebase, and gain inspiration:
Explore the mern-project GitHub topic to see more great projects and templates.
The World Wide Web is saturated with many resources for learning about the MERN stack — and anything, really — but these are some great ones to start with:
While knowing the roadmap for becoming a MERN stack developer is important, understanding the job market demand is just as critical. Many people pursue MERN stack development not just for personal projects but also to secure a job in the field. So, how in-demand are MERN stack developers today?
There are no recent stats specifically tracking the demand for MERN stack developers. However, after searching various job boards — Glassdoor, Himalayas, Indeed, LinkedIn, and Y Combinator’s Work at a Startup — for terms like “mern stack developer,” “fullstack developer,” and “web developer,” I noticed that less than 25 percent of job postings requested the MERN stack, and these are conservative figures.
This suggests that demand for the MERN stack as a whole has declined compared to a few years or a decade ago.
The insights I gathered from the job boards match Google search trends, which show that the search volume for “mern stack developers” far outweighs that of “full stack developer”:
Why the drop in demand? The web development space is consistently evolving as new tools emerge. Certain technologies gain popularity while others fade. For example, jQuery was once the industry standard for JavaScript libraries, which is no longer the case.
One thing is obvious: putting all your eggs in one basket is risky. The MERN stack as a whole may not be as requested, but individual technologies within it are still highly relevant.
For example, a company might need MongoDB or NoSQL experience, and another might require React and Node.js but use PostgreSQL instead of MongoDB.
So, while you may not see “MERN stack” as a job requirement, you will find React, Node, or MongoDB appearing in different combinations across job descriptions.
Because new tools emerge constantly, limiting yourself to a single stack can affect your career path. Instead, focus on:
At the end of the day, startups and midsized companies will always need databases, frontend frameworks, and server-side libraries — but they won’t always choose the tools in the MERN stack. Some will prefer PostgreSQL, Vue, Next.js, or something entirely new. The key is to become a versatile developer who can adapt and learn new technologies quickly to stay ahead of trends.
While the MERN stack may not be as in-demand as before, certain types of companies still hire MERN developers. Startups and mid-sized tech companies, especially those building MVPs and scalable web applications, will likely choose the MERN stack because of its JavaScript-only ecosystem, which speeds up development.
If you’re targeting MERN stack roles, smaller tech companies, digital agencies, and fast-growing startups are where you’re likely to find the most opportunities.
Deploying a Node-based web app or website is the easy part. Making sure your Node instance continues to serve resources to your app is where things get tougher. If you’re interested in ensuring requests to the backend or third-party services are successful, try LogRocket.
LogRocket is like a DVR for web and mobile apps, recording literally everything that happens while a user interacts with your app. Instead of guessing why problems happen, you can aggregate and report on problematic network requests to quickly understand the root cause.
LogRocket instruments your app to record baseline performance timings such as page load time, time to first byte, slow network requests, and also logs Redux, NgRx, and Vuex actions/state. Start monitoring for free.
Install LogRocket via npm or script tag. LogRocket.init()
must be called client-side, not
server-side
$ npm i --save logrocket // Code: import LogRocket from 'logrocket'; LogRocket.init('app/id');
// Add to your HTML: <script src="https://cdn.lr-ingest.com/LogRocket.min.js"></script> <script>window.LogRocket && window.LogRocket.init('app/id');</script>
Hey there, want to help make our blog better?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up nowUse parallel computing in Node.js with worker threads to optimize performance, handle CPU-intensive tasks, and utilize multi-core processors.
Frontend architecture is the foundation of your frontend codebase. Here’s how to optimize the pattern that you choose.
Implement graceful degradation in frontend apps by handling failures, mitigating API timeouts, and ensuring a seamless UX with fallbacks.
Use htmx and Go to build high-performance websites, leveraging server-side rendering and minimal JavaScript for fast and efficient applications.