Real examples of deploying Node.js on Heroku: 3 practical examples

If you’re looking for real, working examples of deploying Node.js on Heroku, you’re in the right place. Too many tutorials wave their hands and skip straight from “git push heroku main” to “it’s live!” with no context. In this guide, you’ll see **examples of deploying Node.js on Heroku: 3 practical examples** that mirror what developers actually ship: a simple API, a full-stack app with a database, and a background worker that handles jobs off the main request cycle. We’ll walk through realistic use cases, show the code and configuration that matter, and call out the gotchas that tend to bite teams in 2024–2025: Node versions, environment variables, build steps, and scaling dynos. Along the way, we’ll add more than three examples in practice—covering logging, scheduled tasks, and zero-downtime config changes—so you can adapt these patterns to your own apps. If you can deploy a Git repo, you can use these examples of Node.js on Heroku in production without guesswork.
Written by
Jamie
Published
Updated

Let’s start with the simplest example of deploying Node.js on Heroku: a tiny Express API that returns JSON. This is the pattern you’ll see in many examples of deploying Node.js on Heroku: 3 practical examples, but we’ll tighten it up for 2024–2025.

Create a project:

printf "node_modules\n.env\n" > .gitignore
npm init -y
npm install express

index.js:

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

const PORT = process.env.PORT || 3000; // Heroku sets PORT

app.get('/', (req, res) => {
  res.json({
    status: 'ok',
    env: process.env.NODE_ENV || 'development',
    time: new Date().toISOString()
  });
});

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

Heroku needs a Procfile to know how to run your app:

web: node index.js

Lock your Node.js version for predictable builds. In 2024–2025, many teams are on Node 20, so your package.json might look like:

{
  "name": "heroku-node-api",
  "version": "1.0.0",
  "main": "index.js",
  "scripts": {
    "start": "node index.js"
  },
  "engines": {
    "node": "20.x"
  },
  "dependencies": {
    "express": "^4.21.0"
  }
}

Then the classic Heroku workflow:

heroku create my-node-api-example
heroku config:set NODE_ENV=production

git add .
git commit -m "Initial API example"
git push heroku main

This is the baseline example of a Node.js deployment on Heroku: one dyno, one process, no database, no build step. Many of the best examples you’ll see online are just variations on this: different routes, middleware, or logging.

Extra example: Adding logging and health checks

To turn this into a more production-like example, add a /health endpoint and structured logs. This gives you another one of those small but important examples of deploying Node.js on Heroku: 3 practical examples you can reuse across projects.

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

app.use((err, req, res, next) => {
  console.error(JSON.stringify({
    level: 'error',
    message: err.message,
    stack: err.stack
  }));
  res.status(500).json({ error: 'Internal server error' });
});

Now your logs play nicely with Heroku log drains and external log analysis tools, which matters once real users start hitting your API.


Example 2: Full-stack Node.js app with Postgres on Heroku

The next step up in examples of deploying Node.js on Heroku: 3 practical examples is a full-stack app: Express backend, templating or React front-end assets, and a Postgres database. This is much closer to what teams actually deploy.

Assume an Express app using pg and server-side rendering (EJS) to keep things focused on deployment.

Install dependencies:

npm install express pg ejs

server.js:

const express = require('express');
const { Pool } = require('pg');

const app = express();
const PORT = process.env.PORT || 3000;

const pool = new Pool({
  connectionString: process.env.DATABASE_URL,
  ssl: process.env.NODE_ENV === 'production' ? { rejectUnauthorized: false } : false
});

app.set('view engine', 'ejs');

app.get('/', async (req, res, next) => {
  try {
    const { rows } = await pool.query('SELECT NOW() AS now');
    res.render('index', { now: rows[0].now });
  } catch (err) {
    next(err);
  }
});

app.use((err, req, res, next) => {
  console.error(err);
  res.status(500).send('Something went wrong');
});

app.listen(PORT, () => {
  console.log(`Web app listening on ${PORT}`);
});

Procfile:

web: node server.js

Attach Postgres on Heroku:

heroku create my-node-fullstack-example
heroku addons:create heroku-postgresql:mini

heroku config:set NODE_ENV=production
heroku config:get DATABASE_URL

Heroku exposes the database connection string as DATABASE_URL, which we used in the Pool config. This pattern shows up in many examples of Heroku deployments, and it’s still the recommended approach.

You can now:

git push heroku main
heroku open

Extra example: Running migrations and one-off tasks

Real apps need schema changes. Another of the best examples of deploying Node.js on Heroku is how you run migrations without breaking production.

Assume you use a simple script with node-pg-migrate or your own SQL runner. Add:

"scripts": {
  "start": "node server.js",
  "migrate": "node scripts/migrate.js"
}

Then on Heroku:

heroku run npm run migrate

That heroku run pattern is one of the most practical examples of how you should handle:

  • Database migrations
  • Backfills and data cleanup
  • One-off scripts (e.g., user imports)

It keeps these tasks outside the web dyno, which is a common best practice in production environments.

Extra example: Serving a built React front-end from Node on Heroku

If you’re using React, Vue, or another front-end framework, a very common example of deploying Node.js on Heroku is: build the front-end, serve static files from Express, and let Node handle API routes.

Add a build step:

"scripts": {
  "build": "npm run build:client",
  "start": "node server.js",
  "heroku-postbuild": "npm run build"
}

Heroku runs heroku-postbuild automatically after dependencies are installed. In 2024–2025, this is still the standard pattern for Node + React deployments, and you’ll see it referenced in many real examples of production setups.


Example 3: Background worker and scheduled jobs on Heroku

The third of our examples of deploying Node.js on Heroku: 3 practical examples moves beyond the web dyno. Real systems offload work to background jobs: sending emails, processing payments, generating reports, or calling external APIs.

Heroku supports this with worker dynos defined in your Procfile.

worker.js:

console.log('Worker booting…');

setInterval(async () => {
  try {
    // Example: poll a queue table or external API
    console.log(`[${new Date().toISOString()}] Worker running task…`);
    // Do work here
  } catch (err) {
    console.error('Worker error:', err);
  }
}, 15 * 1000);

Procfile:

web: node server.js
worker: node worker.js

Deploy as usual, then scale the worker:

heroku ps:scale web=1 worker=1

Now you have a separate dyno doing background work. This is one of the best examples of how to design Heroku-based systems: web dynos stay responsive while workers handle heavy lifting.

Extra example: Using Heroku Scheduler for cron-style jobs

Another very practical example of deploying Node.js on Heroku is to combine a worker script with Heroku Scheduler, which runs commands at intervals (every 10 minutes, hourly, daily).

Create jobs/daily-report.js:

(async () => {
  console.log('Generating daily report at', new Date().toISOString());
  // Query database, send email, write to S3, etc.
  process.exit(0);
})();

Add a script:

"scripts": {
  "start": "node server.js",
  "daily-report": "node jobs/daily-report.js"
}

On Heroku, install Scheduler:

heroku addons:create scheduler:standard

Then in the Heroku dashboard, schedule:

npm run daily-report

This pattern (small Node scripts triggered by Scheduler) shows up in many real examples of production Heroku apps: invoice generation, data exports, nightly syncs, and more.


Putting it together: 6+ real examples you can reuse

By now, we’ve walked through three primary examples of deploying Node.js on Heroku: 3 practical examples, but in practice you’ve seen more than that:

  • A minimal Express API using a web dyno
  • A production-style API with health checks and structured logging
  • A full-stack Node app with Postgres and server-side rendering
  • A Node + React setup using heroku-postbuild for front-end assets
  • A background worker dyno for async processing
  • Scheduled jobs using Heroku Scheduler and small Node scripts
  • One-off tasks and migrations using heroku run

These are not toy snippets; they’re patterns that match how teams actually ship Node.js apps in 2024–2025.

2024–2025 realities you should care about

When you look up examples of deploying Node.js on Heroku: 3 practical examples, a lot of older posts miss changes in the ecosystem. A few current points:

  • Node version drift: Lock your Node version with an engines.node field. New Node LTS releases can change behavior; pinning to 20.x or similar keeps builds predictable.
  • Environment variables over config files: Heroku’s config:set remains the standard. This mirrors the Twelve-Factor App methodology that many universities still teach in modern software engineering courses (see, for example, discussions of cloud-native design at MIT OpenCourseWare).
  • Security and secrets: Never commit .env to Git. Use Heroku config vars and, for sensitive workloads, consider external secret managers.
  • Logging and monitoring: Forward Heroku logs to an external service so you can search, alert, and retain them. The pattern we used with JSON logs fits most logging platforms.

If you’re teaching these patterns or learning them in a classroom context, these are the same practices that show up in modern web engineering curricula at institutions like Harvard’s CS50 Web Programming, which emphasize environment-based configuration, stateless services, and externalized persistence.


FAQ: common questions about real examples of deploying Node.js on Heroku

What are some real examples of deploying Node.js on Heroku that teams use in production?

Common real-world examples of Node.js deployments on Heroku include:

  • Public REST APIs for mobile apps (Express or Fastify)
  • Internal dashboards backed by Postgres and Redis
  • Notification services that send email, SMS, or push alerts via worker dynos
  • Scheduled reporting jobs driven by Heroku Scheduler and small Node scripts

All of these can be built using the patterns in the examples of deploying Node.js on Heroku: 3 practical examples covered above.

Can I use these examples with TypeScript on Heroku?

Yes. The only extra step is a build phase. Add a build script like tsc, output compiled JavaScript to a dist directory, and run that in your Procfile:

web: node dist/server.js

Then add a heroku-postbuild script to compile TypeScript. Many of the best examples of modern Node deployments on Heroku use TypeScript this way.

How do these examples compare to deploying Node.js on other platforms?

The patterns in these examples of deploying Node.js on Heroku: 3 practical examples carry over to other platforms: environment variables for config, separate workers for background jobs, and build steps for front-end assets. The commands and YAML files change, but the architecture stays similar.

Is Heroku still a good choice for Node.js in 2024–2025?

For small to medium apps, prototypes, teaching, and internal tools, yes. It’s still one of the fastest ways to go from Git repo to live URL. If you outgrow it, the patterns from these examples of deploying Node.js on Heroku transfer cleanly to container-based platforms like AWS ECS or Kubernetes.


Where to go next

If you’ve worked through these examples of deploying Node.js on Heroku: 3 practical examples, you already know enough to:

  • Ship a small API for a side project
  • Launch a database-backed app with real users
  • Offload heavy work to background jobs and scheduled tasks

From here, deepen your understanding of cloud architecture, security, and scaling. For broader background on system reliability and best practices in distributed systems, university resources such as Stanford’s online materials and MIT OpenCourseWare are good starting points.

The bottom line: pick one of these examples, fork it, and push it to Heroku. You’ll learn more in an afternoon of shipping a real app than in a week of reading yet another shallow tutorial.

Explore More Node.js Code Snippets

Discover more examples and insights in this category.

View All Node.js Code Snippets