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.
Subscribe for updates
Build better digital experiences with Contentful updates direct to your inbox.