Heroku Node.js Support
Last updated October 31, 2024
Table of Contents
This document describes the general behavior of Heroku as it relates to the recognition and execution of Node.js applications. For a more detailed explanation of how to deploy an application, see Getting Started on Heroku with Node.js.
Activation
The Heroku Node.js buildpack is used when the application has apackage.json
file in the root directory.
Node.js Runtimes
Node versions adhere to Semver, the semantic versioning convention popularized by GitHub. Semver uses a version scheme in the form MAJOR.MINOR.PATCH
.
MAJOR
denotes incompatible API changesMINOR
denotes added functionality in a backwards-compatible mannerPATCH
denotes backwards-compatible bug fixes
Supported Runtimes
Heroku supports the Current version of Node.js and all Active Long-Term-Support (LTS) versions. Heroku supports new releases within 24 hours of the official release from the Node team. As the Node.js release schedule illustrates, Heroku currently supports Node.js versions 18.x
, 20.x
, and 22.x
.
Other Available Runtimes
Because Heroku is based on a standard Ubuntu Linux stack, you can run most Node versions (>= 0.10.0
) on the platform. However, the buildpack’s testing and support revolves around active LTS and Stable releases.
Specifying a Node.js Version
Always specify a Node.js version that matches the runtime that you’re developing and testing with. To find your version locally:
$ node --version
v20.9.0
First, ensure that your application uses the heroku/nodejs
buildpack.
$ heroku buildpacks
=== issuetriage Buildpack URLs
1. heroku/nodejs
To specify the version of Node.js to use on Heroku, use the engines
section of the package.json
. Drop the v
to save only the version number.
{
"name": "example-app",
"description": "a really cool app",
"version": "1.0.0",
"engines": {
"node": "20.x"
}
}
If a Node version isn’t specified in the engines
section, Node.js 22.x
is used automatically.
To get the latest patch updates from Node, we recommend using an x
in the patch. You can also specify a minor range such as 20.9
or an exact version, like 20.9.0
.
Because Node does regular security releases on all supported major versions, we recommend specifying a major range to get security updates automatically, for example, 22.x
.
Specifying a Package Manager
Node.js applications can be built using npm, pnpm, and Yarn. Directions for how to configure each package manager is found below.
Only one package manager should be used with your application.
Using npm
Node.js comes bundled with npm
, so most of the time specifying a separate npm
version isn’t necessary. However, if you intentionally use a different version of npm
locally, specify the same version on Heroku.
{
"name": "example-app",
"description": "a really cool app",
"version": "0.0.1",
"engines": {
"npm": "10.x"
}
}
Using pnpm
If you have a pnpm-lock.yaml
file at the root of your application along with package.json
, Heroku downloads and installs pnpm which will be used to install dependencies and build your application. Specify the version that you use locally so that Heroku uses the same version.
To specify the pnpm version for your application builds, use one of the following methods:
Use the
packageManager
field inpackage.json
{ "name": "example-app", "description": "a really cool app", "version": "1.0.0", "packageManager": "pnpm@9.0.5" }
This method uses Corepack which is preferred for pnpm tooling. The version declared in
package.json
must be exact but it can be configured from a version range with Corepack’s use command (e.g.;corepack use pnpm@9.x
).Use the
engines.pnpm
field inpackage.json
{ "name": "example-app", "description": "a really cool app", "version": "1.0.0", "engines": { "pnpm": "9.0.5" } }
This method allows for version ranges like
9.0
or9.x
to be used. Ranges can be useful for keeping up to date with new releases but are not as safe as exact versions when it comes to reliable builds.
Using Yarn
If you have a yarn.lock
file at the root of your application along with package.json
, Heroku downloads and installs Yarn which will be used to install your dependencies and build your application. Specify the version that you use locally so that Heroku uses the same version.
To specify the Yarn version for your application builds, use one of the following methods:
Use the
packageManager
field inpackage.json
{ "name": "example-app", "description": "a really cool app", "version": "1.0.0", "packageManager": "yarn@4.1.1" }
This method uses Corepack which is preferred for Yarn tooling. The version declared in
package.json
must be exact but it can be configured from a version range with Corepack’s use command (e.g.;corepack use yarn@4.x
).Use the
engines.yarn
field inpackage.json
{ "name": "example-app", "description": "a really cool app", "version": "1.0.0", "engines": { "yarn": "4.1.1" } }
This method allows for version ranges like
4.1
or4.x
to be used. Ranges can be useful for keeping up to date with new releases but are not as safe as exact versions when it comes to reliable builds.
Build Behavior
Node.js applications follow the same build process when using npm, pnpm, or Yarn. Details on these build steps follow.
Package Installation
By default, Heroku installs all dependencies listed in package.json
under dependencies
and devDependencies
.
After running the installation and build steps, Heroku strips out the packages declared under devDependencies
before deploying the application.
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.
Using npm install
If you prefer 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
, you want to use your Heroku cache to speed up your build times. If you don’t use npm install
, disable the build cache.
$ heroku config:set NODE_MODULES_CACHE=false
Only Installing dependencies
You can direct Heroku to only install dependencies
by setting these environment variables.
NPM_CONFIG_PRODUCTION=true
for npmYARN_PRODUCTION=true
for Yarn v1
$ heroku config:set NPM_CONFIG_PRODUCTION=true YARN_PRODUCTION=true
Skip Pruning
Depending on your build process or the target environment, you may need to keep the packages declared under devDependencies
around. The pruning step can be skipped 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
Customizing 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 will be run on Heroku
}
If a heroku-postbuild
script is specified, the build
script does not run.
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."
}
Environment Variables
Your app’s environment is 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
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.
Configuring 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.’
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/
Cache Behavior
Heroku maintains a build cache that persists between builds. This cache stores caches for npm, yarn, and bower.
You can disable all caching for Node.js apps if you prefer.
$ heroku config:set NODE_MODULES_CACHE=false
$ git commit -am 'disable node_modules cache' --allow-empty
$ git push heroku main
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"]
Runtime Behavior
The buildpack puts node
, npm
, and node_modules/.bin
on the PATH
so that you can execute with heroku run or use them directly in a Procfile.
$ cat Procfile
web: npm start
The NODE_ENV
environment variable is set to ‘production’ by default, but you can set it to any arbitrary string.
$ heroku config:set NODE_ENV=staging
Usually, you want NODE_ENV to be ‘production.’ Several modules, including express
, implicitly change their behavior based on NODE_ENV.
Default Web Process Type
First, Heroku looks for a Procfile specifying your process types.
If no Procfile
is present in the root directory of your app during the build process, start your web process by running npm start
, a script that you can specify in package.json
. For example:
"scripts": {
"start": "node server.js"
}
If you only want to run non-web
processes in your app’s formation, explicitly scale web
down and the other process types up. For example:
$ heroku scale web=0 worker=1
Warnings
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.
Add-Ons
No add-ons are provisioned by default. If you need a database for your app, add one explicitly.
$ heroku addons:create heroku-postgresql
Multi-Buildpack Behavior
When using the Node.js buildpack with other buildpacks, it automatically exports the node
, npm
, and node_modules
binaries onto the PATH
for subsequent buildpacks to consume.
Going Further
The Heroku Node.js buildpack is open source. For a better technical understanding of how the buildpack works, check out the source code at github.com/heroku/heroku-buildpack-nodejs.