How to Host Nodejs on Heroku

How to Host Node.js on Heroku Hosting a Node.js application on Heroku is one of the most efficient and beginner-friendly ways to deploy modern web applications to the cloud. Heroku, a cloud platform as a service (PaaS), abstracts away the complexities of server management, allowing developers to focus on writing code rather than configuring infrastructure. Whether you’re building a REST API, a rea

Oct 30, 2025 - 13:06
Oct 30, 2025 - 13:06
 0

How to Host Node.js on Heroku

Hosting a Node.js application on Heroku is one of the most efficient and beginner-friendly ways to deploy modern web applications to the cloud. Heroku, a cloud platform as a service (PaaS), abstracts away the complexities of server management, allowing developers to focus on writing code rather than configuring infrastructure. Whether you’re building a REST API, a real-time chat application, or a full-stack web app, deploying your Node.js project to Heroku provides rapid scalability, built-in monitoring, and seamless integration with Git-based workflows.

Node.js, with its non-blocking I/O model and vast ecosystem of packages via npm, has become the backbone of modern JavaScript development. When paired with Heroku’s intuitive deployment pipeline, developers can go from local development to a live, publicly accessible application in under ten minutes. This tutorial provides a comprehensive, step-by-step guide to hosting Node.js applications on Heroku — from initial setup to advanced optimization — ensuring your app runs reliably, securely, and at scale.

Step-by-Step Guide

Prerequisites

Before you begin, ensure you have the following tools installed and configured on your local machine:

  • Node.js (v18 or higher recommended)
  • npm or yarn (package manager)
  • Git (version control system)
  • Heroku CLI (command-line interface)

To verify your setup, open your terminal and run:

node --version

npm --version

git --version

heroku --version

If any of these commands return an error, install the missing tool from its official website. For the Heroku CLI, visit Heroku’s CLI documentation for installation instructions based on your operating system.

Step 1: Create a Node.js Application

If you don’t already have a Node.js project, create one using the following commands:

mkdir my-node-app

cd my-node-app

npm init -y

This creates a new directory and initializes a package.json file with default settings. Next, install Express.js — the most popular web framework for Node.js:

npm install express

Create a file named server.js in your project root and add the following minimal web server code:

const express = require('express');

const app = express();

const PORT = process.env.PORT || 3000;

app.get('/', (req, res) => {

res.send('Hello from Node.js on Heroku!');

});

app.listen(PORT, () => {

console.log(Server is running on port ${PORT});

});

This code sets up a basic HTTP server using Express that listens on a port defined by the environment variable PORT — a critical requirement for Heroku, which dynamically assigns ports at runtime. If PORT is not set (e.g., locally), it defaults to 3000.

Step 2: Add a Start Script to package.json

Heroku uses the start script defined in package.json to determine how to launch your application. Open your package.json and update the scripts section:

{

"name": "my-node-app",

"version": "1.0.0",

"description": "A simple Node.js app hosted on Heroku",

"main": "server.js",

"scripts": {

"start": "node server.js",

"dev": "nodemon server.js"

},

"dependencies": {

"express": "^4.18.2"

}

}

Heroku automatically runs npm start during deployment. If this script is missing, Heroku will fail to start your app. Note: We’ve also added a dev script using nodemon for local development, which we’ll cover later.

Step 3: Create a .gitignore File

To prevent unnecessary files from being committed to version control, create a .gitignore file in your project root:

node_modules/

.env

.DS_Store

npm-debug.log*

This ensures that dependencies (installed locally), environment variables, and system-specific files are excluded from your Git repository. Heroku installs dependencies from package.json, so you never need to push the node_modules folder.

Step 4: Initialize a Git Repository

Initialize a Git repository in your project directory and commit your files:

git init

git add .

git commit -m "Initial commit"

Heroku integrates directly with Git, so every deployment is triggered by a git push to the Heroku remote.

Step 5: Create a Heroku App

Log in to your Heroku account via the CLI:

heroku login

Follow the prompts to authenticate. Then, create a new Heroku app:

heroku create your-app-name

Replace your-app-name with a unique name of your choice. If you omit the name, Heroku will generate one for you automatically. The command also adds a remote called heroku to your Git repository, linking your local project to the cloud app.

To verify the remote was added, run:

git remote -v

You should see output similar to:

heroku  https://git.heroku.com/your-app-name.git (fetch)

heroku https://git.heroku.com/your-app-name.git (push)

Step 6: Deploy to Heroku

Deploy your application by pushing your code to Heroku’s remote:

git push heroku main

If your default branch is named master instead of main, use:

git push heroku master

Heroku will detect your Node.js app, install dependencies from package.json, and automatically build a release. You’ll see logs in your terminal indicating the build process:

Counting objects: 5, done.

Delta compression using up to 8 threads.

Compressing objects: 100% (4/4), done.

Writing objects: 100% (5/5), 552 bytes | 552.00 KiB/s, done.

Total 5 (delta 0), reused 0 (delta 0)

remote: Compressing source files... done.

remote: Building source:

remote:

remote: -----> Node.js app detected

remote: -----> Creating runtime environment

remote: -----> Installing Node.js v18.17.0

remote: -----> Installing dependencies

remote: Installing node modules

remote: added 55 packages, and audited 56 packages in 4s

remote: -----> Build succeeded!

remote: -----> Discovering process types

remote: Procfile declares types -> web

remote:

remote: -----> Compressing...

remote: Done: 21.4M

remote: -----> Launching...

remote: Released v1

remote: https://your-app-name.herokuapp.com/ deployed to Heroku

remote:

remote: Verifying deploy... done.

To https://git.heroku.com/your-app-name.git

* [new branch] main -> main

Step 7: Open Your Live App

Once the deployment completes, open your app in the browser:

heroku open

This command launches your app in your default browser. You should see the message: “Hello from Node.js on Heroku!”

Step 8: View Logs and Debug

To monitor your app’s runtime behavior, view real-time logs using:

heroku logs --tail

This is invaluable for debugging errors, tracking request patterns, or identifying performance bottlenecks. You’ll see output like:

2024-05-15T10:20:30.123456Z app[web.1]: Server is running on port 45678

2024-05-15T10:20:31.456789Z heroku[router]: at=info method=GET path="/" host=your-app-name.herokuapp.com request_id=abc123 fwd="192.168.1.1" dyno=web.1 connect=1ms service=5ms status=200 bytes=123 protocol=https

Step 9: Add Environment Variables (Optional but Recommended)

For sensitive data like API keys, database URLs, or JWT secrets, use environment variables. Heroku allows you to set them via CLI:

heroku config:set API_KEY=your-secret-key

heroku config:set DATABASE_URL=mongodb://localhost:27017/mydb

In your code, access them using process.env.VARIABLE_NAME:

const apiKey = process.env.API_KEY;

Never hardcode secrets into your source files. Heroku encrypts config vars at rest and in transit.

Step 10: Scale Your App (Optional)

By default, Heroku runs your app on a single free dyno (a lightweight container). To upgrade performance, scale your dyno:

heroku ps:scale web=1

For production apps, consider upgrading to a paid dyno type:

heroku dyno:type hobby

Or use the Heroku Dashboard to manage dyno types and scaling visually.

Best Practices

Use a Procfile for Explicit Process Types

Although Heroku can auto-detect a Node.js app from package.json, it’s a best practice to create a Procfile in your project root to explicitly define the process type:

web: node server.js

The web process type tells Heroku this is a web application that should be exposed to HTTP traffic. This ensures consistent behavior across environments and prevents ambiguity during deployment.

Always Use Environment Variables for Configuration

Hardcoding configuration values like database URLs, API keys, or port numbers makes your app less portable and more vulnerable to security breaches. Always use process.env.VARIABLE_NAME to reference configuration. For local development, create a .env file and use the dotenv package:

npm install dotenv

At the top of your server.js, add:

require('dotenv').config();

And create a .env file:

PORT=3000

API_KEY=your-local-key

Remember to keep .env in your .gitignore — it should never be committed to version control.

Optimize Your package.json for Production

Use dependencies for packages required at runtime and devDependencies for tools like nodemon, jest, or eslint:

npm install nodemon --save-dev

Heroku only installs dependencies during deployment, reducing build time and minimizing attack surface. Avoid installing dev tools in production.

Set a Node.js Version in package.json

To avoid unexpected behavior due to version mismatches, specify the Node.js version your app requires:

{

"engines": {

"node": "18.x"

}

}

Heroku will use this version during build. You can check available versions with:

heroku buildpacks:info heroku/nodejs

Implement Proper Error Handling

Uncaught exceptions and unhandled promise rejections can crash your Node.js server. Wrap critical code in try-catch blocks and use process event listeners:

process.on('uncaughtException', (err) => {

console.error('Uncaught Exception:', err);

process.exit(1);

});

process.on('unhandledRejection', (reason, promise) => {

console.error('Unhandled Rejection at:', promise, 'reason:', reason);

process.exit(1);

});

This ensures your app restarts gracefully or fails safely, preventing silent crashes.

Enable HTTP Compression

Reduce bandwidth usage and improve load times by enabling Gzip compression in Express:

const compression = require('compression');

app.use(compression());

Install the package:

npm install compression

This compresses responses (HTML, CSS, JS) before sending them to the client, improving performance without additional infrastructure.

Use a Reverse Proxy or CDN for Static Assets

Heroku’s filesystem is ephemeral — any files written to disk during runtime are lost when the dyno restarts. For static assets like images, CSS, or JS files, serve them through Express or use a CDN like Cloudflare or Amazon S3.

For small apps, serve static files directly:

app.use(express.static('public'));

Place assets in a public/ folder. For larger apps, offload static assets to a CDN to reduce dyno load and improve global delivery.

Monitor Performance and Uptime

Heroku provides basic monitoring via the Dashboard and logs, but for deeper insights, integrate third-party tools like:

  • New Relic – Application performance monitoring
  • LogDNA – Advanced log aggregation
  • Sentry – Error tracking and alerting

Install these as Heroku add-ons via CLI or Dashboard. For example:

heroku addons:create newrelic:standard

Use Health Checks and Readiness Probes

Heroku doesn’t provide built-in health checks, but you can implement a simple endpoint to verify your app is alive:

app.get('/health', (req, res) => {

res.status(200).json({ status: 'OK', uptime: process.uptime() });

});

Integrate this endpoint with monitoring tools or external uptime services like UptimeRobot to receive alerts if your app becomes unresponsive.

Tools and Resources

Essential Heroku Add-Ons

Heroku’s ecosystem of add-ons extends functionality without requiring complex infrastructure setup:

  • Heroku Postgres – Managed PostgreSQL database
  • Redis Cloud – In-memory data store for caching and sessions
  • ClearDB MySQL – MySQL database for relational data
  • SendGrid – Email delivery service
  • LogDNA – Log management and analytics
  • New Relic – Performance monitoring

Install any add-on via CLI:

heroku addons:create heroku-postgresql:hobby-dev

Access database credentials via process.env.DATABASE_URL.

Development Tools

  • Nodemon – Automatically restarts your server on file changes during development
  • ESLint – Code quality and style enforcement
  • Postman – API testing and debugging
  • Visual Studio Code – Recommended IDE with built-in terminal and Git integration

Documentation and Learning Resources

Performance Optimization Tools

  • Webpack – Bundles JavaScript assets for production
  • Helmet – Secures Express apps with HTTP headers
  • Rate-Limit – Prevents brute-force attacks
  • Winston – Advanced logging library

Install and configure these tools to enhance security, scalability, and maintainability:

npm install helmet rate-limit winston

Real Examples

Example 1: REST API with Express and MongoDB

Deploying a RESTful API on Heroku is common. Here’s a simplified example:

// server.js

const express = require('express');

const mongoose = require('mongoose');

const cors = require('cors');

const dotenv = require('dotenv');

dotenv.config();

const app = express();

app.use(cors());

app.use(express.json());

// Connect to MongoDB

mongoose.connect(process.env.MONGODB_URI)

.then(() => console.log('MongoDB connected'))

.catch(err => console.error('MongoDB connection error:', err));

// Routes

app.get('/api/users', (req, res) => {

res.json([{ id: 1, name: 'John Doe' }]);

});

const PORT = process.env.PORT || 5000;

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

Set the MongoDB URI as an environment variable:

heroku config:set MONGODB_URI=mongodb+srv://username:password@cluster.mongodb.net/mydb

Deploy with git push heroku main. Heroku handles the Node.js runtime, and MongoDB Atlas (or another cloud provider) handles the database.

Example 2: Real-Time Chat App with Socket.IO

Heroku supports WebSockets, making it ideal for real-time applications. Install Socket.IO:

npm install socket.io

Update your server:

const express = require('express');

const http = require('http');

const socketIo = require('socket.io');

const app = express();

const server = http.createServer(app);

const io = socketIo(server);

app.use(express.static('public'));

io.on('connection', (socket) => {

console.log('User connected');

socket.on('chat message', (msg) => {

io.emit('chat message', msg);

});

socket.on('disconnect', () => {

console.log('User disconnected');

});

});

const PORT = process.env.PORT || 3000;

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

Heroku’s routing layer supports WebSockets by default. No additional configuration is needed. Clients connect via:

const socket = io('https://your-app-name.herokuapp.com');

Example 3: Multi-Stage Deployment with GitHub Actions

For teams, automate deployment using GitHub Actions. Create .github/workflows/deploy.yml:

name: Deploy to Heroku

on:

push:

branches: [ main ]

jobs:

deploy:

runs-on: ubuntu-latest

steps:

- uses: actions/checkout@v4

- name: Deploy to Heroku

uses: akhileshns/heroku-deploy@v3.12.12

with:

heroku_api_key: ${{ secrets.HEROKU_API_KEY }}

heroku_app_name: "your-app-name"

heroku_email: "your-email@example.com"

buildpack: heroku/nodejs

Store your Heroku API key in GitHub Secrets as HEROKU_API_KEY. Every push to main triggers an automatic deployment — ideal for CI/CD pipelines.

FAQs

Is hosting Node.js on Heroku free?

Yes, Heroku offers a free tier that includes one dyno (a lightweight container) and 550 free dyno hours per month. This is sufficient for small projects, personal portfolios, or testing. However, free dynos sleep after 30 minutes of inactivity, which means the first request after sleep may take 5–10 seconds to respond. For production apps, upgrade to a paid dyno type.

Why does my app sleep on Heroku?

Heroku’s free dynos automatically sleep after 30 minutes of inactivity to conserve resources. This is a limitation of the free tier. To prevent sleep, you can use third-party services like UptimeRobot to ping your app every 5–10 minutes, or upgrade to a Hobby ($7/month) or Professional dyno.

Can I use a custom domain with Heroku?

Yes. Purchase a domain from a registrar like Namecheap or Google Domains, then add it in the Heroku Dashboard under Settings → Domains. Heroku will provide a DNS target (e.g., your-app-name.herokuapp.com). Point your domain’s CNAME record to that target. SSL certificates are automatically provisioned via Let’s Encrypt.

How do I update my app after the initial deployment?

Make changes locally, commit them to Git, and push to Heroku:

git add .

git commit -m "Update homepage"

git push heroku main

Heroku automatically rebuilds and redeploys your app. No manual restart is required.

What if my app crashes on Heroku?

Run heroku logs --tail to view real-time logs. Common causes include:

  • Missing start script in package.json
  • Incorrect port binding (must use process.env.PORT)
  • Uncaught exceptions or unhandled promise rejections
  • Missing environment variables
  • Database connection failures

Fix the issue locally, test, then redeploy.

Can I use a database with Heroku?

Absolutely. Heroku offers managed database add-ons like Heroku Postgres, Redis Cloud, and ClearDB MySQL. Connect via environment variables. For example, Heroku Postgres provides a DATABASE_URL that you can use directly with ORMs like Sequelize or Mongoose.

Does Heroku support HTTPS?

Yes. All Heroku apps are served over HTTPS by default. Heroku automatically provisions and renews SSL certificates via Let’s Encrypt. No manual configuration is needed.

How much does it cost to host on Heroku?

Heroku offers tiered pricing:

  • Free – 550 dyno hours/month, limited features
  • Hobby – $7/month – 550 dyno hours/month, no sleep, 1 dyno
  • Standard – $25–$500/month – Multiple dynos, advanced monitoring
  • Performance – $250–$500/month – High-performance dynos, dedicated resources

Additional costs may apply for add-ons like databases, storage, or email services.

Can I deploy multiple Node.js apps on one Heroku account?

Yes. Each app is independent and has its own domain, environment variables, and dynos. Create a new app for each project using heroku create with a unique name.

How do I delete a Heroku app?

Run:

heroku apps:destroy --app your-app-name --confirm your-app-name

This permanently deletes the app and all associated data. Backup any important information first.

Conclusion

Hosting a Node.js application on Heroku is a streamlined, reliable, and scalable solution for developers of all experience levels. From the simplicity of a single git push to the robustness of automated deployments and managed add-ons, Heroku removes the operational overhead traditionally associated with server management. By following the steps outlined in this guide — from setting up your project and configuring environment variables to deploying with best practices and monitoring performance — you can confidently launch and maintain production-ready Node.js applications.

While Heroku’s free tier is ideal for learning and prototyping, upgrading to paid plans unlocks features like persistent dynos, advanced monitoring, and enhanced security — essential for real-world applications. Pair Heroku with modern development tools like GitHub Actions, ESLint, and Sentry to build a professional, maintainable stack.

As JavaScript continues to dominate web development, mastering the deployment of Node.js apps on platforms like Heroku is no longer optional — it’s a core skill for modern developers. Use this guide as your foundation, experiment with real projects, and leverage the vast ecosystem of tools and add-ons to take your applications further. The cloud is no longer a mystery — it’s your launchpad.