Deep-dive on the Next Gen Platform. Join the Webinar!

Skip Navigation
Show nav
Dev Center
  • Get Started
  • Documentation
  • Changelog
  • Search
  • Get Started
    • Node.js
    • Ruby on Rails
    • Ruby
    • Python
    • Java
    • PHP
    • Go
    • Scala
    • Clojure
    • .NET
  • Documentation
  • Changelog
  • More
    Additional Resources
    • Home
    • Elements
    • Products
    • Pricing
    • Careers
    • Help
    • Status
    • Events
    • Podcasts
    • Compliance Center
    Heroku Blog

    Visit the Heroku Blog

    Find news and updates from Heroku in the blog.

    Visit Blog
  • Log inorSign up
Hide categories

Categories

  • Heroku Architecture
    • Compute (Dynos)
      • Dyno Management
      • Dyno Concepts
      • Dyno Behavior
      • Dyno Reference
      • Dyno Troubleshooting
    • Stacks (operating system images)
    • Networking & DNS
    • Platform Policies
    • Platform Principles
  • Developer Tools
    • Command Line
    • Heroku VS Code Extension
  • Deployment
    • Deploying with Git
    • Deploying with Docker
    • Deployment Integrations
  • Continuous Delivery & Integration (Heroku Flow)
    • Continuous Integration
  • Language Support
    • Node.js
      • Working with Node.js
      • Troubleshooting Node.js Apps
      • Node.js Behavior in Heroku
    • Ruby
      • Rails Support
      • Working with Bundler
      • Working with Ruby
      • Ruby Behavior in Heroku
      • Troubleshooting Ruby Apps
    • Python
      • Working with Python
      • Background Jobs in Python
      • Python Behavior in Heroku
      • Working with Django
    • Java
      • Java Behavior in Heroku
      • Working with Java
      • Working with Maven
      • Working with Spring Boot
      • Troubleshooting Java Apps
    • PHP
      • PHP Behavior in Heroku
      • Working with PHP
    • Go
      • Go Dependency Management
    • Scala
    • Clojure
    • .NET
      • Working with .NET
  • Databases & Data Management
    • Heroku Postgres
      • Postgres Basics
      • Postgres Getting Started
      • Postgres Performance
      • Postgres Data Transfer & Preservation
      • Postgres Availability
      • Postgres Special Topics
      • Migrating to Heroku Postgres
    • Heroku Key-Value Store
    • Apache Kafka on Heroku
    • Other Data Stores
  • AI
    • Working with AI
  • Monitoring & Metrics
    • Logging
  • App Performance
  • Add-ons
    • All Add-ons
  • Collaboration
  • Security
    • App Security
    • Identities & Authentication
      • Single Sign-on (SSO)
    • Private Spaces
      • Infrastructure Networking
    • Compliance
  • Heroku Enterprise
    • Enterprise Accounts
    • Enterprise Teams
    • Heroku Connect (Salesforce sync)
      • Heroku Connect Administration
      • Heroku Connect Reference
      • Heroku Connect Troubleshooting
  • Patterns & Best Practices
  • Extending Heroku
    • Platform API
    • App Webhooks
    • Heroku Labs
    • Building Add-ons
      • Add-on Development Tasks
      • Add-on APIs
      • Add-on Guidelines & Requirements
    • Building CLI Plugins
    • Developing Buildpacks
    • Dev Center
  • Accounts & Billing
  • Troubleshooting & Support
  • Integrating with Salesforce
  • Language Support
  • Node.js
  • Node.js Behavior in Heroku
  • Node.js Classic Buildpack Builds

Node.js Classic Buildpack Builds

Last updated March 17, 2025

Table of Contents

  • Main Steps
  • Build Failures
  • Environment Variables
  • Add a Build Step to the Build Process
  • Only Install dependencies
  • Use npm install instead of npm ci
  • Skip Pruning
  • Custom Caching
  • Disable Caching
  • Use Private Dependencies
  • Customize Binary Downloads
  • Additional Reading

Heroku’s Node.js buildpacks have different build behavior depending on whether an app uses classic or Cloud Native Buildpacks (CNB).

This article describes the build behavior for apps using Heroku’s classic Node.js buildpack and how to customize the build process. Node.js applications follow the same build process when using npm, pnpm, or Yarn package managers.

This article is only applicable to apps use the classic buildpack. For Node.js CNB apps, see Node.js Cloud Native Buildpack Builds.

Main Steps

The main steps in the build process are:

  1. Install dependencies
  2. Prune dependencies
  3. Cache dependencies

By default, Heroku installs all dependencies listed in package.json under dependencies and devDependencies. You can choose to only install dependencies.

Heroku uses the lockfiles (package-lock.json, pnpm-lock.yaml, or yarn.lock) to install the expected dependency tree. Check those files into Git to ensure the same dependency versions across environments. If you use npm, Heroku uses npm ci to set up the build environment. You can also choose to npm install instead of npm ci.

After running the installation, Heroku prunes out the packages declared under devDependencies before deploying the application. You can choose to skip pruning.

Heroku maintains a build cache that persists between builds. This cache stores modules for npm, yarn, pnpm, and bower. Heroku stores the node_modules and bower_components directories by default. You can customize where things are cached, or disable caching altogether.

If your app has a build step that you want to run when you deploy, you can use a build script in package.json. You can also run scripts specifically before or after other Heroku build steps, like before installing dependencies.

Build Failures

If a build fails, the Node.js buildpack identifies common issues in Node applications and provides warnings with best practice recommendations.

We also maintain a document to help troubleshoot common Node.js issues.

Environment Variables

Your app’s config vars are available during the build, so you can adjust build behavior based on the values of environment variables. For example:

$ heroku config:set MY_CUSTOM_VALUE=foobar

Configure npm

npm reads configuration from any environment variables beginning with NPM_CONFIG.

You can also control npm’s behavior via a .npmrc file in your project’s root.

When NPM_CONFIG_PRODUCTION is true, npm automatically runs all scripts in a subshell where NODE_ENV is ‘production.’

Add a Build Step to the Build Process

If your app has a build step that you want to run when you deploy, you can use a build script in package.json.

"scripts": {
  "start": "node index.js",
  "build": "webpack"
}

If package.json has a build script that requires customization for Heroku, define a heroku-postbuild script, which runs instead of the build script.

"scripts": {
  "start": "node index.js",
  "build": "ng build",
  "heroku-postbuild": "ng build --prod" // this command will run on Heroku
}

If a heroku-postbuild script is specified, the build script does not run.

Add Steps Before or After Heroku-Specific Build Steps

While each package manager supports standard preinstall and postinstall scripts, it’s possible that you want to run scripts only before or after other Heroku build steps. For example, to configure npm, git, or ssh before Heroku installs dependencies, or to build production assets after dependencies are installed.

For Heroku-specific actions, use the heroku-prebuild, heroku-postbuild, and heroku-cleanup scripts.

"scripts": {
  "heroku-prebuild": "echo This runs before Heroku installs dependencies.",
  "heroku-postbuild": "echo This runs after Heroku installs dependencies, but before Heroku prunes and caches dependencies.",
  "heroku-cleanup": "echo This runs after Heroku prunes and caches dependencies."
}

Build Flags

If your app runs a build step, make sure that it’s used for development and production. If it’s not, use the build flag environment variable to set flags for the build script. For example, your build step is:

"scripts": {
  "build": "ng build"
}

You can set the NODE_BUILD_FLAGS environment variable.

$ heroku config:set NODE_BUILD_FLAGS="--prod"

Setting this variable runs ng build --prod in the build step instead.

Only Install dependencies

You can direct Heroku to only install dependencies instead of also installing devDependencies by setting these environment variables.

  • NPM_CONFIG_PRODUCTION=true for npm
  • YARN_PRODUCTION=true for Yarn v1
$ heroku config:set NPM_CONFIG_PRODUCTION=true YARN_PRODUCTION=true

Use npm install instead of npm ci

To use npm install instead of npm ci to create the build environment, you can use the USE_NPM_INSTALL environment variable to let the buildpack know. Run:

$ heroku config:set USE_NPM_INSTALL=true

If you use npm install, use your Heroku cache to speed up your build times. If you don’t use npm install, disable the build cache.

Skip Pruning

Depending on your build process or the target environment, you must to keep the packages declared under devDependencies around. You can skip the pruning step depending on the target NODE_ENV or if environment variables to opt-out of this step have been set.

For all package managers, if NODE_ENV is any other value, the pruning step is skipped.

Skip pruning using npm

$ heroku config:set NPM_CONFIG_PRODUCTION=false

Skip pruning using pnpm

$ heroku config:set PNPM_SKIP_PRUNING=true

Skip pruning using Yarn v1

$ heroku config:set YARN_PRODUCTION=false

Skip pruning using Yarn v2 and above

$ heroku config:set YARN2_SKIP_PRUNING=true

Custom Caching

Heroku stores the node_modules and bower_components directories by default. You can override these defaults by providing a cacheDirectories array in your top-level package.json.

For example, if you build inside client and server sub-directories.

"cacheDirectories": ["client/node_modules", "server/node_modules"]

Or perhaps your app needs a large dictionary of some sort, stored in data/dictionary.txt.

"cacheDirectories": ["data"]

Disable Caching

You can disable all caching for Node.js apps by setting the NODE_MODULES_CACHE config var:

$ heroku config:set NODE_MODULES_CACHE=false
$ git commit -am 'disable node_modules cache' --allow-empty
$ git push heroku main

Use Private Dependencies

If pulling from a private dependency source, such as NPM Enterprise or Gemfury, the project must configure an alternate registry with access tokens.

Add the private registry URL to .npmrc. In this case, we specify NPM‘s registry even though it’s public, which replaces this scope with the scope used for the private. Then, add the registry URL that points to using the auth token.

echo "@scope:registry=https://registry.npmjs.org" >> .npmrc
echo -e "//registry.npmjs.org/:_authToken=\${NPM_TOKEN}" >> .npmrc

This registry URL is specific to the npm registry, but other private package registries can have similar URLs. Consult with the private registry’s documentation.

The .npmrc looks like:

@scope:registry=https://registry.npmjs.org
//registry.npmjs.org/:_authToken=${NPM_TOKEN}

Verify the addition of NPM_TOKEN to the Heroku config so that the build can access the token and install the private package.

heroku config:set NPM_TOKEN=PRIVATE_NPM_TOKEN

Customize Binary Downloads

You can customize where Node and yarn binaries are downloaded by setting environment variables NODE_BINARY_URL and YARN_BINARY_URL to a custom URL. For instance:

$ heroku config:set NODE_BINARY_URL=https://s3.amazonaws.com/your-custom-binary-url/

Additional Reading

  • Heroku Node.js Support Reference
  • Node.js Behavior in Heroku
  • Slug Compiler

Keep reading

  • Node.js Behavior in Heroku

Feedback

Log in to submit feedback.

Node.js Cloud Native Buildpack Builds Node.js Cloud Native Buildpack Builds

Information & Support

  • Getting Started
  • Documentation
  • Changelog
  • Compliance Center
  • Training & Education
  • Blog
  • Support Channels
  • Status

Language Reference

  • Node.js
  • Ruby
  • Java
  • PHP
  • Python
  • Go
  • Scala
  • Clojure
  • .NET

Other Resources

  • Careers
  • Elements
  • Products
  • Pricing
  • RSS
    • Dev Center Articles
    • Dev Center Changelog
    • Heroku Blog
    • Heroku News Blog
    • Heroku Engineering Blog
  • Twitter
    • Dev Center Articles
    • Dev Center Changelog
    • Heroku
    • Heroku Status
  • Github
  • LinkedIn
  • © 2025 Salesforce, Inc. All rights reserved. Various trademarks held by their respective owners. Salesforce Tower, 415 Mission Street, 3rd Floor, San Francisco, CA 94105, United States
  • heroku.com
  • Legal
  • Terms of Service
  • Privacy Information
  • Responsible Disclosure
  • Trust
  • Contact
  • Cookie Preferences
  • Your Privacy Choices