Published on May 25, 2025

The MERN stack combines MongoDB, Express, React, and Node.js to create a full development stack consisting of a client, server, and database.
It's popular because it uses JavaScript on both the front and back end and a flexible database system, speeding up development time with a unified codebase.
This post explains the MERN stack and provides a full tutorial and example code.
A technology stack is a combination of tools (programming languages, frameworks, and libraries) that are brought together to build and run a software application. The MERN stack is one such stack: a predefined grouping of four software development technologies that work well together to cover every part of a web application. The MERN stack consists of:
MongoDB is a NoSQL database that uses JSON-like documents to store data, rather than tables, and has a flexible schema allowing you to define and modify data models on the fly. It handles storage of data and database interactions.
MongoDB uses BSON (binary JSON), which works natively with JavaScript. This means you don't have to transform data between the client, server, and database, so no extra mappings are needed (unlike with SQL). MongoDB simplifies full-stack development in the MERN stack, especially when used with an ODM (object-document mapper) like Mongoose, which adds structure, validation, and easier queries.
Express is a lightweight Node.js framework built to handle routes, requests, and middleware. In MERN, Node.js and Express together form the back end, which powers your app’s API, business logic, and database queries.
React is a frontend JavaScript library for building user interfaces; it powers the front end in the MERN stack. React lets you build dynamic, component-based UIs that update when state changes.
You can manage local or global state with built-in tools like useState or useContext, or, if you need more complex state management, opt for libraries like Redux. Libraries like Fetch or Axios can connect React to your backend Express API. React provides a declarative way to build user interfaces: it allows you to efficiently render dynamic parts of the UI, resulting in fast and modern-looking applications.
Node.js allows you to run JavaScript on the server and handles requests with a single-threaded event loop. This allows it to handle thousands of different connections at the same time, which gives you faster operations for tasks like reading files, accessing databases, and handling API requests.
When building your back end, you can choose between a REST or GraphQL API to connect your front end to the back end. Node.js provides performance with its non-blocking, event-driven architecture, and Express brings simplicity and structure in setting up your server with minimal configuration.

Here's how the data would flow through a typical MERN application stack when a user submits a form:
React handles the user interface: user input is stored in a state variable, and when the user clicks to submit a form, an event is triggered in the browser.
React sends the data to the Express back end (running on Node.js) via an HTTP request, typically using either Fetch or Axios.
Express receives the request and performs some data validation and processing (if set up by the developer), and then interacts with the MongoDB database, normally via an ORM, to save or retrieve data.
Once the database operation is complete, Express sends a response back to React.
React receives the response and updates the UI; this could be a confirmation to the user or rendering new data.

Web development is complex. There are innumerable tools, layers of abstraction, and a growing list of languages and frameworks to learn. Choosing the tools you'll use to build an application, and knowing they'll play well together before you start building, is a challenge.
As Leonardo da Vinci supposedly said, "Simplicity is the ultimate sophistication."
The MERN stack provides a simple answer to this problem by combining well-proven tools: using JavaScript as a universal language across the entire stack, the most popular UI library, and a flexible document-based database.
Each part of the MERN stack is battle-tested and widely adopted, which means if you get stuck, there's a large community on hand to help with any issues. There are also lots of open-source packages and tutorials and a wealth of knowledge when it comes to best practices. It's all JavaScript, so there's no language switching and libraries can be shared between the front and back end, leading to faster development cycles.
The MERN stack is naturally compatible with most cloud environments, making it easy and affordable to deploy. The database can be hosted with MongoDB Atlas, which simplifies database management and integrates well with other cloud providers. You can deploy technologies like React and Node on a server, or you could choose to go serverless for extra speed and scalability.
To demonstrate how the MERN stack works, this tutorial shows you how to build a book review app that displays books to the user and allows them to leave reviews.
Before you begin, make sure you have MongoDB installed or Atlas set up and have your username and password ready so you can connect to the database.
You can clone the example GitHub repo to run and adapt the code developed in this tutorial.
The MERN stack isn't a prepackaged solution: while you can be confident that MongoDB, Express, React, and Node.js will integrate well together, you still need to install each part yourself and write your app code to connect them.
To start, create a project folder named mern-book-app to host all of the project code (including the front end and back end), and navigate to it:
mkdir mern-book-app
cd mern-book-app
Create a new Express HTTP server in the server directory with the following commands:
npx express-generator server --no-view --git
cd server
npm install
Now install the mongoose, dotenv, and cors packages from npm. Mongoose is a popular object document mapper (ODM) that makes it easier to work with MongoDB using schemas and models. dotenv loads environment variables, and the CORS package enables cross-origin resource sharing, allowing the front end (running on a different port) to communicate with the back end without being blocked by the browser.npm install mongoose dotenv cors
Create a .env file:
touch .env
And add the MongoDB connection string containing your database credentials, host, port, and database name:
MONGO_URI="mongodb://username:password@host:port/database"
Update the bin/www file to load environment variables, by adding the following line to the top of the file:
require('dotenv').config();
At the top of app.js add the following code to connect to MongoDB:
Also enable CORS and JSON parsing by adding the following code to app.js, below the var app=express() line:
Next, create the book model. Create a models/Book.js file with the following Mongoose schema code:
Now create the review model, which references the Book model (to tie the data together). Create a models/Review.js file and add the following code:
Each review has a reference to the book that was reviewed; a userReview, which is a text string; and a rating, which is a number.
In the routes/index.js file, completely replace the existing code with the following:
The above code sets up three routes: /books to get all of the books in the database, a GET request /books/:id/reviews to get reviews for a specific book, and a POST request /books/:id/reviews to submit a review and tie it to a book ID.
Your app will need some initial book data stored in the database. Create the following database seeder (a script that “seeds” a database with data) in the file scripts/seedBooks.js:
Note that this script deletes all existing entries in the database. Run the database seeder with the command:
node scripts/seedBooks.js
If this script doesn't work, check that your MongoDB server is running, that the credentials are correct and that you’ve specified the right database name.
Run the following command to start the Express server:
npm run start
Postman is an API testing tool that you can use to check the backend API is working by making a HTTP GET request to http://localhost:3000/books:

In production apps, you could add a data validation library like Zod to ensure that users can only submit valid data and reduce errors.
Change directory to the root of mern-book-app and create a new React app in the client directory using Vite — make sure you specify React as the framework and JavaScript as the variant when creating the project:
npm create vite@latest client --template react
cd client
npm install
Install the Axios library to make API calls to the back end:
npm install axios
src/App.jsx will load the books from the back end. Replace the contents of this file with the following code:
Create a components directory within the src directory. In there, create a BookList.jsx file containing the following code, which will render the books, with a button to open up a form to leave a review and a button to see current reviews stored in the database:
Create an additional file in the src/components directory named BookReviewForm.jsx and add the following code, which displays an input to leave a book review and rating:
To get the project running, start the server, and then run the following command in your front end:
npm run dev
Now head to http://localhost:5173 in your browser to test the project out.

Rather than writing your own image upload code (and code to optimize, save, resize, and deliver media files), you can use the Contentful content delivery API to upload images for your books and link them with the MongoDB database ID.
The following example code shows you how you can integrate Contentful with the MERN app created above so that it provides the interface for managing images for books, and links them to the records in your MongoDB database. The source for this code builds on the client example above, and is available in the client_contentful directory of the example project
To start, head over to Contentful and log in or create a free account.
In the top tab bar, click on Content model. From here you’ll need to create a new Book content type in your content model, by clicking Create content type on the right:

Next, add a Media type field named bookCover to the Book model:

Set the Name and Field ID to bookCover, and select One file as the media type, then click Add and configure to confirm:

Next add a Text type field with a Name and Field ID of bookId that will be used to link the image in Contentful to the book in your MongoDB database.
Finally, click Save in the top right-hand corner:

Now go to the Content tab and click to add a new entry under book. Upload your book cover by clicking on Add media and then publish the asset. Now, below that, add a bookId (MongoDB _id from a book in your database), and finally click Publish on the right.

Repeat the process for the other books you have saved in your database.
Now you’ve added your assets to Contentful you can connect to retrieve the data through the content delivery API. Contentful provides SDKs for popular languages and frameworks to do this for you. Install the Contentful JavaScript SDK by running the following command in the client directory:npm install contentful
In the client/src directory, create a helper file to connect to Contentful named contentfulClient.js and add the following code:
You will need to add the following environment variables to your .env file (you may need to create one in the client directory if it isn't already present):
VITE_CF_SPACE_ID is the Contentful space ID, which is used to identify the space where your content is stored.
VITE_CF_CMA_TOKEN is the Contentful Content Management API token, which allows write access to your Contentful space.
VITE_CF_SPACE_ID={your value here}
VITE_CF_CMA_TOKEN={your value here}
Note that you'll need to use the space and token details from your own Contentful account, which you will be able to find under API keys in Settings.
Now in App.js replace the code in the useEffect hook, which fetches the books, with the following:
This fetches the book covers from Contentful and the books from the database, then merges the books with the correct book covers based on the MongoDB _id field, it’s important here that the ids you have in MongoDB match what you have entered into Contentful, if you seed the database again the ids will differ.
Lastly, in the BookList.jsx file, add the following piece of code immediately above the line <h2>{book.title}</h2>:
This takes the coverUrl of the book and displays it with an img tag.
If you refresh the app you should see something like the below:

With this connection to Contentful, editors can now update book image covers for the app without developer involvement.

The MERN stack is ideal for building fast, dynamic single-page applications (SPAs).These applications load a single HTML file, which then dynamically updates content without refreshing the page. React provides this interactivity with its state handling and frontend routing system.
MERN is a good fit for solo developers and small teams looking to build their product as quickly as possible. MongoDB allows you to iterate quickly and remain flexible on the schema and adapt your data model over time, making it ideal for MVPs or startups where the domain is liable to change through different iterations.
The MERN stack is also largely unopinionated, allowing you to decide the overall structure and architectural pattern for your application. This is appealing to teams that need full control over how their code works, especially when compared with more opinionated frameworks like Remix or Next.
MERN’s core differentiator from other JavaScript stacks is the choice of MongoDB. When you need to store relational data, it's best not to use a non-relational database (like MongoDB, a document database), as, among other things, MongoDB doesn't have good support for operations like joins or transactions. If you need a stack that’s better for relational data, you might want to go for the PERN stack, which uses PostgreSQL for the database layer.
Typically, the MERN stack is used to build client-side rendered (CSR) web apps, which is not optimal for SEO (as it's harder for Google to crawl and index your web pages). SEO is enhanced by server-side rendering (SSR), so it's generally better to use a full-stack framework like Next, Remix, or Nuxt as they provide SSR out of the box.
The MERN stack isn't the only web development stack. Below is a table detailing a few of the other options, which come with their own set of benefits and use cases:
Stack | Technologies | Ideal for |
|---|---|---|
MERN | MongoDB, Express.js, React, Node.js | Dynamic single page applications (SPAs), dashboards, CRUD apps (Create, Read, Update, Delete) |
PERN | PostgreSQL, Express.js, React, Node.js | Data-heavy apps, relational data enterprise software |
MEVN | MongoDB, Express.js, Vue.js, Node.js | Progressive web apps (PWAs), frontend-heavy UX |
MEAN | MongoDB, Express.js, Angular, Node.js | Large-scale enterprise SPAs |
JAMstack | JavaScript, APIs, Markup | Static sites, blogs, marketing sites |
A significant portion of this tutorial is dedicated to building your back end — but much of this work is increasingly unnecessary. SaaS APIs for ecommerce, social media, communication, and content management relieve you of the development time and investment and ongoing maintenance and hosting fees required to provide your own backend services.
Contentful provides you with a customizable content platform for uploading and managing omnichannel content that can be delivered to websites, apps, newsletters, billboards, and even AI agents using our REST and GraphQL APIs and super-fast global CDN.
By leveraging the content tools Contentful provides, you can focus your MERN stack code on the unique functionality of your app, and leave the hosting and security of your content curation and delivery to us.
Inspiration for your inbox
Subscribe and stay up-to-date on best practices for delivering modern digital experiences.