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:
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
{
"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:
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):
brew install heroku/brew/heroku
For Windows: Download the installer from Heroku's CLI page.
For Ubuntu/Debian:
sudo snap install heroku --classic
3. Login to Heroku from CLI
Once installed, login to your Heroku account:
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:
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:
git push heroku main
If you're working on a branch other than main
(like master
), use:
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:
heroku ps:scale web=1
4. Open Your Deployed Application
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:
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
:
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:
heroku config
Database Configuration
MongoDB Example
If you're using MongoDB with Mongoose, here's how to configure it with Heroku:
- Add MongoDB as a Heroku add-on (or use MongoDB Atlas):
heroku addons:create mongolab
- Get your MongoDB URI:
heroku config:get MONGODB_URI
- Use it in your Express app:
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
// 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
{
"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
# 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:
heroku logs --tail
The --tail
flag keeps the log stream open so you can see logs in real-time.
Checking App Status
heroku ps
Restarting Your Application
If your app is experiencing issues, you can restart it:
heroku restart
Common Issues and Troubleshooting
Application Crashes
If your application crashes immediately after deployment, check:
- Ensure your
PORT
is configured correctly - Check that all dependencies are included in
package.json
- Make sure environment variables are set properly
Memory Issues
If your app is crashing due to memory limitations (common with free tier):
- Optimize your code for lower memory usage
- Consider upgrading to a paid Heroku plan
"Application Error" in Browser
If you see an "Application Error" when visiting your app:
- Check the logs:
heroku logs --tail
- Make sure your app is running:
heroku ps
- 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:
-
Preparing your Express application for deployment
- Configuring dynamic port
- Creating a Procfile
- Setting up package.json
-
Setting up Heroku
- Creating an account
- Installing the CLI
- Logging in
-
Deploying your application
- Creating a Heroku app
- Pushing your code
- Scaling dynos
-
Working with environment variables and databases
- Setting config vars
- Connecting to MongoDB
-
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
- Official Heroku Node.js Support Guide
- Heroku Dev Center - Getting Started with Node.js
- Heroku Command Line Interface (CLI) Documentation
- Managing Environment Variables in Node.js
Exercises
-
Basic Deployment: Create a simple Express "Hello World" app and deploy it to Heroku.
-
Environment Variables: Modify your Express app to use an environment variable for a greeting message, then set it on Heroku.
-
Database Integration: Create an Express app with MongoDB integration (using Mongoose) and deploy it to Heroku with MongoDB Atlas as the database.
-
API with Authentication: Build and deploy a simple API that uses environment variables for JWT secret keys.
-
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! :)