How to deploy an existing web app built using MongoDB, ExpressJS, Node.js, and Reactjs (often called as MERN stack) on Heroku
In this article, I will describe how to take an existing Web Application that is build using MongoDB, ExpressJS, Node.js, and React (often called as MERN stack) on a deployment service like Heroku. If you have an existing application built using the same tech stack, you can definitely skip the process in which I show you to quickly build a web application and go straight on to the deployment part. For the rest of you, please continue to read.
To continue to follow this tutorial there are requirements that you will need to build the demo application and then deploy it on Heroku.
- Node.js/npm installed
- Heroku account
For MongoDB, we are going to use a cloud based service like mLab which provides database as a service. It has a free tier, and having an account there will be time saving.
Building a Full-stack app using MERN
Building the Backend
I am going to take you through building a web application using MERN Stack. To start, please create an empty directory and type the following commands in the order they are specified.
server.js file inside the root of the directory. This file will server us the backend file for us.
Now, I made following changes in
package.json for this program to work.
To see if everything is working, run the command
npm start server that we just defined in
package.json as a script. If there are no errors, you will get the following result. Visit the following url:
Please note that onwards Express version
4.16.0 body parser middleware function is a built-in middleware and there is no need to import it as a separate dependency. Body parser middleware is required to handle incoming AJAX requests that come in the form of JSON payloads or urlencoded payloads.
Models with Mongoose
I will start by creating a database model called
Book inside the file
models/Books.js. This will resemble a schema of what to expect from the user when adding information to our application.
I am using
mongoose to define the schema above. Mongoose is an ODM (Object Document Mapper). It allows you to define objects with a strongly typed schema that is mapped as a MongoDB collection. This schema architecture allows us to provide an organized shape to the document inside the MongoDB collection.
bookSchema we are defining two fields: a
title which indicates the title of the book and an
author representing the name of the author of the book. Both these fields are
Our application is going to need some routes that will help the client app to communicate with the server application and perform CRUD (Create, Read, Update, Delete) operations. I am defining all the business logic that works behind every route in a different file. Conventionally, named as controllers. Create a new file
The business logic or you can say the controller logic behind the application is nothing but the methods that will work on a specific route. There are five functions in total. Each has its own use. I am requiring our Book model, previously created, as it provides functions for us to query CRUD operations to the database. A mongoose query can be executed in two ways, by providing a callback function or by using
.then() function which also indicates that mongoose support promises. I am using the promising approach above to avoid the nuisance caused by nested callbacks (and commonly known as callback hell).
Next step is to use these methods in our routes inside
routes/ directory. Create a new file called
I have separated the concerned routes that match a specific URL. For example, routes that are starting with
:id routing parameter are defined above together in the file. Open
index.js in the same directory and add the following.
I am adding a prefix
/api/books before the routes. This way, you can only access them as
For this to work, I am going to import book routes in the
server.js file after every other middleware defined and before we have bootstrapped the server.
Also remove the default route
app.get('/')... that was previously created. We are soon going to serve the application's front end here on the default route.
Connecting with Database using mLab
I am going to use mlab to host the database of our application on the cloud. Once you create an account, your dashboard will look similar to mine. I already have few sandboxes running, so do not mind them.
To create a new one, click on the button
Create New under MongoDB deployments. After that, you select the plan type Sandbox which provides the free tier up to 500MB.
After the MongoDB deployment is created, a database user is required by the mlab to have you connect to this database. To create one now, visit the ‘Users’ tab and click the ‘Add database user’ button.
Now copy the string provided by mlab such as:
and add the
dbpassword you just entered to create the new user. I am going to save these credentials as well as the string given by mlab to connect to the database inside a file called
You can replace the
dbpassword. Now to define the connection with mlab string we are again going to use mongoose. Create a new file inside
We are importing the same database URI string that we just exported in
config. I am going to require this file inside our
server.js before any middleware is defined.
Now run the server again and if you get the following message, that means your database is gracefully connected to the web server.
Building the FrontEnd with React
To build the user interface of our application, I am going to
create-react-app. Run the following command to generate a react application inside a directory called
Once the scaffolding process is complete, run
npm run start after traversing inside the client directory from your terminal, and see if everything works or not. If you get a screen like below that means everything is top-notch.
Install two dependencies from
npm that we need to in order for the client to work.
You are going to need axios to make AJAX requests to the server.
react-router-dom is for switching between navigation routes.
You can download the whole source code or just the client from this Github repository. 👇
I am not going to walk you through every component and reusable component I have built in this application. I am only going to take you through what needs to be done connect the React app to Node.js server, the build process and then deploying it.
The main frontend file,
App.js looks like this:
Next, I have created an
API.js inside the
utils directory which we handle all the requests and fetching data, in simple terms AJAX requests between our client and the server.
We also have
pages and a separate
components directory. The
pages contain those files that are going to display the content when we add a book and its author in our list using a form to submit the data to the backend. The form itself uses different reusable components which are built separately. The sole purpose of doing this is to follow best practices that are convenient to understand the source code and a common practice in the React community.
There are two pages
Details. Let us go through them.
We are defining a local state to manage data and pass it on to the API from the component. Methods like
loadBooks are making AJAX requests through the API calls we defined inside
utils/API.js. Next is the details page.
It shows the books I have added in my list. To use it, first we are going to connect it with Node.js.
Connecting React and Node
There are two build steps we have to undergo through in making a connection between our client side and server side. First, open the
package.json file inside the
client directory and enter a proxy value that points to the same URL on which server is serving the API.
Next step is to run the command
yarn build inside the client directory such that it builds up the project. If you haven't run this command before in this project, you will notice a new directory suddenly appears.
We also need to make two changes to our backend, to serve this
builddirectory. The reason we are doing this is to deploy our full stack application later on Heroku as one. Of course, you can two deployment servers where one is serving the REST API such as our backend and the other serves the client end, the build folder we just created.
routes/index.js and add the following line.
Next, open the
server.js to in which we add another line using Express built-in middleware that serves static assets.
Now you can open your terminal and run the following command.
This will trigger our server at url
http://localhost:5000. Visit it using a browser and see your MERN stack app in action like below. For brevity, I haven't much styled but go ahead and showcase your CSS skills.
To verify that the data from our application is being added to the database, go to your mlab MongoDB deployment. You will notice a collection appearing with the name of
books. Open it and you can see the data you have just submitted through the form. Here is how mine looks like.
I already have two records.
Since everything is running locally without any problem, we can move to the next part.
Deploying on Heroku
This is our final topic in this tutorial. Now, all you need is to have a free Heroku account and Heroku toolbelt to run the whole deployment process from your terminal.
The Heroku Command Line Interface (CLI) makes it easy to create and manage your Heroku apps directly from the terminal. It’s an essential part of using Heroku. ~ Official Documentation
To download the Heroku CLI interface visit this link. Depending on your operating system, you can download the packager. You can also choose a simpler method that is to install the cli interface using npm.
npm install -g heroku
After you go through the download and installation process, you can verify that everything has installed correctly.
package.json by adding the following script.
Login to your Heroku account with credentials by running command
heroku login like below.
Next, create a
Procfile in the root folder with following value.
Once you are logged in traverse to the project directory of your MERN stack application. Run the following command to create a Heroku instance of your app. Make sure you are in the main directory and not in the client folder.
Before we go on to prepare our project for Heroku, I am going to use
git to push our current project. This is the most common and safe way to use it with Heroku cli interface. Run the following commands in the order described.
When this command runs successfully, it gives you an app id like this. Remember this app id as we are going to use it set our existing mlab MongoDB URI.
Next step is to connect the existing mlab deployment from our Heroku app.
You can also use the free tier of mlab provided by Heroku using the following command in case you haven’t deployed your database previously. This command must only be run in case you are not already using mlab for your Mongodb deployment.
You can verify that the configuration value has been set by running:
password in above commands are your mlab credentials that have been discussed on how to set up them in previous sections of this article. Next step is to push the whole app to Heroku.
This points to Heroku remote instead of
origin. This above command sends the source code to Heroku and from then Heroku reads
package.json only to install
dependencies. That is the reason we defined
start script rather using the than
server one because Heroku or a deployment server has no use of development environment dependencies such as
Finishing the building of your project may look similar to mine.
You can then visit the URL given by Heroku like below. Do notice the already existing data that we deployed using local server in the previous section.
There are many deployment techniques that you can try on Heroku. The technique described in this article is just one of them. I hope you have this article has helped you out.