How to deploy Node.js app to Heroku

Deploying Node.js applications to Heroku provides easy Git-based deployment with automatic builds, environment management, and scalability. With over 12 years of Node.js experience since 2014 and as the creator of CoreUI, I’ve deployed numerous Node.js services to Heroku. Heroku’s platform-as-a-service handles infrastructure management, allowing developers to focus on application code with simple deployment workflow. This approach offers quick deployment with minimal configuration and automatic SSL, domain management, and monitoring.

Use Heroku CLI with Git to deploy Node.js applications with Procfile configuration and environment variables.

Install Heroku CLI:

# macOS
brew tap heroku/brew && brew install heroku

# Ubuntu
curl https://cli-assets.heroku.com/install.sh | sh

# Windows
# Download installer from heroku.com

# Login
heroku login

Prepare Node.js app:

// index.js
const express = require('express')
const app = express()
const PORT = process.env.PORT || 3000

app.use(express.json())

app.get('/', (req, res) => {
  res.json({ message: 'Hello from Heroku!' })
})

app.get('/health', (req, res) => {
  res.json({ status: 'healthy' })
})

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

Package.json configuration:

{
  "name": "my-nodejs-app",
  "version": "1.0.0",
  "main": "index.js",
  "scripts": {
    "start": "node index.js",
    "dev": "nodemon index.js",
    "test": "jest"
  },
  "engines": {
    "node": "20.x",
    "npm": "10.x"
  },
  "dependencies": {
    "express": "^4.18.2",
    "dotenv": "^16.3.1"
  },
  "devDependencies": {
    "nodemon": "^3.0.2"
  }
}

Procfile:

web: node index.js

Deploy to Heroku:

# Create Heroku app
heroku create my-nodejs-app

# Or create with specific region
heroku create my-nodejs-app --region eu

# Add PostgreSQL database (optional)
heroku addons:create heroku-postgresql:mini

# Set environment variables
heroku config:set NODE_ENV=production
heroku config:set API_KEY=your-api-key
heroku config:set DATABASE_URL=your-database-url

# Deploy
git add .
git commit -m "Initial deployment"
git push heroku main

# Open app
heroku open

# View logs
heroku logs --tail

Environment variables:

# Set config vars
heroku config:set SECRET_KEY=mysecret
heroku config:set REDIS_URL=redis://localhost:6379

# View all config vars
heroku config

# Get specific config var
heroku config:get SECRET_KEY

# Remove config var
heroku config:unset SECRET_KEY

Advanced configuration:

// app.js
require('dotenv').config()
const express = require('express')
const app = express()

// Trust proxy for HTTPS on Heroku
app.set('trust proxy', 1)

// Environment-specific configuration
const config = {
  port: process.env.PORT || 3000,
  env: process.env.NODE_ENV || 'development',
  databaseUrl: process.env.DATABASE_URL,
  redisUrl: process.env.REDIS_URL
}

// Health check endpoint for Heroku
app.get('/health', (req, res) => {
  res.status(200).json({
    status: 'ok',
    environment: config.env,
    uptime: process.uptime()
  })
})

// Graceful shutdown
process.on('SIGTERM', () => {
  console.log('SIGTERM signal received: closing HTTP server')
  server.close(() => {
    console.log('HTTP server closed')
    process.exit(0)
  })
})

const server = app.listen(config.port, () => {
  console.log(`Server running in ${config.env} mode on port ${config.port}`)
})

module.exports = app

Database setup:

# Add PostgreSQL
heroku addons:create heroku-postgresql:mini

# Get database URL
heroku config:get DATABASE_URL

# Connect to database
heroku pg:psql

# Run migrations
heroku run npm run migrate

Scaling:

# Scale web dynos
heroku ps:scale web=2

# Scale to free tier
heroku ps:scale web=1

# View dyno status
heroku ps

# Restart all dynos
heroku restart

CI/CD with GitHub:

# Connect to GitHub
heroku git:remote -a my-nodejs-app

# Enable automatic deploys (via Heroku Dashboard)
# Settings > Deploy > GitHub > Connect > Enable Automatic Deploys

# Or use Heroku CI
# Create app.json

app.json for review apps:

{
  "name": "my-nodejs-app",
  "description": "My Node.js application",
  "repository": "https://github.com/user/repo",
  "logo": "https://example.com/logo.png",
  "keywords": ["node", "express", "api"],
  "env": {
    "NODE_ENV": {
      "value": "production"
    },
    "SECRET_KEY": {
      "generator": "secret"
    }
  },
  "addons": [
    {
      "plan": "heroku-postgresql:mini"
    }
  ],
  "buildpacks": [
    {
      "url": "heroku/nodejs"
    }
  ]
}

Custom domain:

# Add custom domain
heroku domains:add www.example.com

# View domains
heroku domains

# SSL is automatic with Heroku

Best Practice Note

Specify Node.js version in package.json engines field. Use Procfile to define process types. Store secrets in Heroku config vars, never in code. Use DATABASE_URL and other add-on environment variables. Implement graceful shutdown for SIGTERM. Trust proxy for HTTPS. Enable automatic deploys from GitHub for CI/CD. Use review apps for pull request testing. This is how we deploy CoreUI Node.js backends to Heroku—Git-based deployment with environment configuration, automatic SSL, and zero-downtime deployments with dyno scaling.


Speed up your responsive apps and websites with fully-featured, ready-to-use open-source admin panel templates—free to use and built for efficiency.


About the Author