Skip to main content

Express Heroku Deployment

Introduction

Deploying your Express.js application to a production environment is a crucial step in the web development process. While developing locally is great for testing and building features, your application needs to be accessible to users across the internet to provide actual value.

Heroku is one of the most popular cloud platforms for deploying web applications, especially for beginners and small to medium-sized projects. It provides a straightforward way to deploy your Express applications without needing to understand complex server infrastructure.

In this guide, you'll learn how to:

  • Prepare your Express.js application for Heroku deployment
  • Set up a Heroku account and install necessary tools
  • Deploy your application to Heroku
  • Configure environment variables
  • Monitor your deployed application

Prerequisites

Before we begin, make sure you have:

  • A working Express.js application on your local machine
  • Node.js and npm installed
  • Git installed and basic understanding of Git commands
  • A free Heroku account (we'll cover how to create one)

Preparing Your Express Application for Heroku

1. Configure the Port

Heroku dynamically assigns a port for your application to listen on. Update your Express app to use the port provided by Heroku's environment variable:

javascript
const express = require('express');
const app = express();

// Your middleware and routes go here

// Use Heroku's provided PORT or default to 3000 for local development
const PORT = process.env.PORT || 3000;

app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});

2. Add a Procfile

Create a file named Procfile (no file extension) in the root of your project. This file tells Heroku how to run your application:

web: node app.js

Replace app.js with your main server file (e.g., server.js, index.js).

3. Update package.json

Ensure your package.json file has:

  • A start script that Heroku will use to run your application
  • A proper engines field specifying the Node.js version
json
{
"name": "my-express-app",
"version": "1.0.0",
"description": "My Express application",
"main": "app.js",
"scripts": {
"start": "node app.js",
"dev": "nodemon app.js"
},
"engines": {
"node": "16.x"
},
"dependencies": {
"express": "^4.17.1"
// other dependencies
}
}

4. Initialize Git Repository

If your project is not already a Git repository, initialize one:

bash
git init
git add .
git commit -m "Initial commit for Heroku deployment"

Setting Up Heroku

1. Create a Heroku Account

Visit Heroku's website and sign up for a free account if you don't have one already.

2. Install the Heroku CLI

The Heroku Command Line Interface (CLI) allows you to create and manage your Heroku apps directly from the terminal.

For macOS (using Homebrew):

bash
brew install heroku/brew/heroku

For Windows: Download the installer from Heroku's CLI page.

For Ubuntu/Debian:

bash
sudo snap install heroku --classic

3. Login to Heroku from CLI

Once installed, login to your Heroku account:

bash
heroku login

This will open a browser window where you can log in to your Heroku account.

Deploying Your Express Application

1. Create a Heroku App

Create a new Heroku application:

bash
heroku create my-express-app

Replace my-express-app with your preferred app name. If you don't specify a name, Heroku will generate a random one for you.

2. Deploy Your Application

Deploy your application to Heroku using Git:

bash
git push heroku main

If you're working on a branch other than main (like master), use:

bash
git push heroku master:main

3. Ensure Dynos are Running

Heroku uses "dynos" which are lightweight containers for running your app. Make sure you have at least one dyno running:

bash
heroku ps:scale web=1

4. Open Your Deployed Application

bash
heroku open

This command will open your application in a browser.

Configuration and Environment Variables

Setting Environment Variables

Sensitive information like API keys, database credentials, and other configuration values should not be hardcoded in your application. Instead, use Heroku's environment variables:

bash
heroku config:set DB_URI=mongodb://username:password@host:port/database
heroku config:set API_KEY=your_api_key

In your Express application, access these variables using process.env:

javascript
const dbUri = process.env.DB_URI;
const apiKey = process.env.API_KEY;

// Use these variables in your application

Viewing Environment Variables

To see all environment variables set for your application:

bash
heroku config

Database Configuration

MongoDB Example

If you're using MongoDB with Mongoose, here's how to configure it with Heroku:

  1. Add MongoDB as a Heroku add-on (or use MongoDB Atlas):
bash
heroku addons:create mongolab
  1. Get your MongoDB URI:
bash
heroku config:get MONGODB_URI
  1. Use it in your Express app:
javascript
const mongoose = require('mongoose');

// Get the URI from environment variables
const mongoURI = process.env.MONGODB_URI || 'mongodb://localhost:27017/myapp';

// Connect to MongoDB
mongoose.connect(mongoURI)
.then(() => console.log('MongoDB connected'))
.catch(err => console.log('MongoDB connection error:', err));

Real-World Example: Deploying a Todo API

Let's go through a complete example of deploying a simple Todo API built with Express and MongoDB:

1. Todo API Application Code

javascript
// app.js
const express = require('express');
const mongoose = require('mongoose');
const cors = require('cors');

const app = express();

// Middleware
app.use(cors());
app.use(express.json());

// MongoDB connection
const mongoURI = process.env.MONGODB_URI || 'mongodb://localhost:27017/todoapp';
mongoose.connect(mongoURI)
.then(() => console.log('MongoDB connected'))
.catch(err => console.log('MongoDB connection error:', err));

// Todo Model
const Todo = mongoose.model('Todo', new mongoose.Schema({
text: { type: String, required: true },
completed: { type: Boolean, default: false },
createdAt: { type: Date, default: Date.now }
}));

// Routes
app.get('/', (req, res) => {
res.send('Todo API is running');
});

// Get all todos
app.get('/api/todos', async (req, res) => {
try {
const todos = await Todo.find().sort({ createdAt: -1 });
res.json(todos);
} catch (err) {
res.status(500).json({ error: err.message });
}
});

// Create a new todo
app.post('/api/todos', async (req, res) => {
try {
const newTodo = new Todo({
text: req.body.text
});
const savedTodo = await newTodo.save();
res.status(201).json(savedTodo);
} catch (err) {
res.status(400).json({ error: err.message });
}
});

// Toggle todo completion status
app.put('/api/todos/:id', async (req, res) => {
try {
const todo = await Todo.findById(req.params.id);
todo.completed = !todo.completed;
await todo.save();
res.json(todo);
} catch (err) {
res.status(400).json({ error: err.message });
}
});

// Delete a todo
app.delete('/api/todos/:id', async (req, res) => {
try {
await Todo.findByIdAndDelete(req.params.id);
res.json({ message: 'Todo deleted' });
} catch (err) {
res.status(400).json({ error: err.message });
}
});

// Port configuration
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});

2. Package.json

json
{
"name": "todo-api",
"version": "1.0.0",
"description": "A simple Todo API",
"main": "app.js",
"scripts": {
"start": "node app.js",
"dev": "nodemon app.js"
},
"engines": {
"node": "16.x"
},
"dependencies": {
"cors": "^2.8.5",
"express": "^4.17.1",
"mongoose": "^6.0.13"
},
"devDependencies": {
"nodemon": "^2.0.15"
}
}

3. Procfile

web: node app.js

4. Deployment Steps

bash
# Initialize git if not already done
git init
git add .
git commit -m "Todo API ready for Heroku deployment"

# Create a Heroku app
heroku create todo-express-api-demo

# Add MongoDB add-on
heroku addons:create mongolab:sandbox

# Deploy to Heroku
git push heroku main

# Start the app
heroku ps:scale web=1

# Open the app in browser
heroku open

Monitoring and Maintenance

Viewing Logs

To see logs from your application:

bash
heroku logs --tail

The --tail flag keeps the log stream open so you can see logs in real-time.

Checking App Status

bash
heroku ps

Restarting Your Application

If your app is experiencing issues, you can restart it:

bash
heroku restart

Common Issues and Troubleshooting

Application Crashes

If your application crashes immediately after deployment, check:

  1. Ensure your PORT is configured correctly
  2. Check that all dependencies are included in package.json
  3. Make sure environment variables are set properly

Memory Issues

If your app is crashing due to memory limitations (common with free tier):

  1. Optimize your code for lower memory usage
  2. Consider upgrading to a paid Heroku plan

"Application Error" in Browser

If you see an "Application Error" when visiting your app:

  1. Check the logs: heroku logs --tail
  2. Make sure your app is running: heroku ps
  3. Ensure your server is listening on the correct port

Summary

In this guide, we've covered how to deploy an Express.js application to Heroku:

  1. Preparing your Express application for deployment

    • Configuring dynamic port
    • Creating a Procfile
    • Setting up package.json
  2. Setting up Heroku

    • Creating an account
    • Installing the CLI
    • Logging in
  3. Deploying your application

    • Creating a Heroku app
    • Pushing your code
    • Scaling dynos
  4. Working with environment variables and databases

    • Setting config vars
    • Connecting to MongoDB
  5. Monitoring and maintaining your application

Heroku offers a fantastic platform for beginners to deploy their Express applications quickly and without complex server management. While it has its limitations, especially on the free tier, it's an excellent starting point for learning about deployment and making your applications accessible to the world.

Additional Resources

  1. Official Heroku Node.js Support Guide
  2. Heroku Dev Center - Getting Started with Node.js
  3. Heroku Command Line Interface (CLI) Documentation
  4. Managing Environment Variables in Node.js

Exercises

  1. Basic Deployment: Create a simple Express "Hello World" app and deploy it to Heroku.

  2. Environment Variables: Modify your Express app to use an environment variable for a greeting message, then set it on Heroku.

  3. Database Integration: Create an Express app with MongoDB integration (using Mongoose) and deploy it to Heroku with MongoDB Atlas as the database.

  4. API with Authentication: Build and deploy a simple API that uses environment variables for JWT secret keys.

  5. Performance Monitoring: Add application monitoring to your deployed app using a service like New Relic (they have a free tier for Heroku).



If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)