Make sure to push your lockfiles (package-lock.json, pnpm-lock.yaml, or yarn.lock) to your repository and keep them updated. This ensures that the dependencies are installed correctly.
Node.js Buildpack on App Platform
Last verified 24 Jun 2026
App Platform is a fully managed Platform-as-a-Service (PaaS) that deploys applications from Git repositories or container images. It automatically builds, deploys, and scales components while handling all underlying infrastructure.
App Platform supports two ways to build an image for your app: Cloud Native Buildpacks and Dockerfiles.
When you give App Platform access to your code, it defaults to using a Dockerfile if one is present in the root of the directory or specified in the app spec. Otherwise, App Platform checks your code to determine what language or framework it uses. If it supports the language or framework, it chooses an appropriate resource type and uses the proper buildpack to build the app and deploy a container.
App Platform uses the heroku-buildpack-nodejs buildpack for detecting and building your Node.js applications and applications using Node.js frameworks such as Express.js, Next.js, and Nuxt.js.
Node.js Applications using Buildpacks
App Platform looks for any of the following files to detect a Node.js application:
package.jsonpackage-lock.jsonyarn.lockpnpm-lock.yaml
If App Platform detects more than one package manager lockfile, it selects one to use during build time. The order of preference is yarn.lock, pnpm-lock.yaml, then package-lock.json. If all three files are present, Yarn is preferred.
Current Buildpack Version and Supported Runtimes
App Platform uses version 341 of the Heroku Node.js buildpack. The buildpack supports running most Node.js runtime versions (>= 0.10.0) on the platform, but it is recommended to use the active LTS and Stable versions since these have higher test coverage.
The buildpack supports the following Node.js runtime versions:
- Ubuntu-22
- 4.x-19.x
- 20.0.0-20.9.0
- 20.16.0-20.20.2
- 21.0.0-21.7.3
- 22.0.0-22.22.2
- 23.0.0-23.11.1
- 24.0.0-24.14.1
- 25.0.0-25.9.0
App Platform uses Node.js 22.x by default if you do not specify a Node.js version in the engines section.
Specify a Node.js Engine
App Platform has updated the Node.js default version from v20 to v22. This is because v22 is the current stable LTS version and v20 is now in maintenance phase. Best practices for pinning the Node.js version in the package.json for apps should be followed in order to avoid build failures.
You can specify your desired Node.js version in the engines section of package.json.
package.json{
"engines": {
"node": "16.x"
}
}Specify Package a Manager
App Platform supports npm, Yarn, and pnpm to build the Node.js applications.
We recommend using only one package manager in your application to avoid any conflicts.
npm
If you have a package-lock.json or package.json at the root of your application, App Platform uses the npm package manager.
App Platform defaults to installing the current version of npm as designated by the Node.js release. You can customize the npm version used by specifying the version in the engines section of your package.json:
package.json{
"engines": {
"npm": "~1.0.20"
}
}yarn
If you have yarn.lock at the root of your application along with package.json, App Platform uses yarn to build your application. You can specify the yarn version in packageManager section of your package.json, like this:
package.json{
"packageManager": "[email protected]"
}This method uses Corepack which is preferred for Yarn tooling. The version defined in package.json must be exact, but can be configured from a version range with Corepack’s use command, for example, corepack use [email protected].
You can also specify a yarn version in the engines section of your package.json:
package.json{
"engines": {
"yarn": "^0.14.0"
}
}pnpm
If you have pnpm-lock.yaml at the root of your application along with package.json, App Platform uses pnpm to build your application. You can specify which pnpm version in the packageManager section of your package.json, like this:
package.json{
"packageManager": "[email protected]"
}This method uses Corepack, which is preferred for pnpm tooling. The version defined in package.json must be exact, but you can configure a version range with Corepack’s use command, for example, corepack use [email protected].
You can also specify a pnpm version in the engines section of your package.json, like this:
package.json{
"engines": {
"pnpm": "9.0.5"
}
}Build Behaviour
App Platform uses the same build process regardless of the package manager used. All the dependencies listed in package.json under dependencies and devDependencies are installed by default. However, after the build steps, the packages declared under devDependencies are stripped before application deployment.
Use npm install
If you use npm, it uses npm ci to set up the build environment.
If you prefer to use npm install instead of npm ci, set the USE_NPM_INSTALL environment variable with a BUILD_TIME scope in your app’s spec, like this:
app.yamlservices:
- name: web
git:
repo: "https://github.com/example/repo"
branch: master
envs:
- key: USE_NPM_INSTALL
scope: BUILD_TIME
value: "true"Disable NODE_MODULES cache
If you don’t use npm or you don’t want to cache Node_modules, declare a NODE_MODULES_CACHE environment variable in your app spec and set it to false, like this:
app.yamlservices:
- name: web
git:
repo: "https://github.com/example/repo"
branch: master
envs:
- key: NODE_MODULES_CACHE
scope: BUILD_TIME
value: "false"Skip devDependencies
To disable the installation of devDependencies, set these environment set NPM_CONFIG_PRODUCTION to true if you are using npm, or YARN_PRODUCTION to true if you are using yarn, like this:
app.yamlservices:
- name: web
git:
repo: "https://github.com/example/repo"
branch: master
envs:
- key: NPM_CONFIG_PRODUCTION
scope: BUILD_TIME
value: "true"Skip Pruning
The build process prunes the devDependencies before application deployment. If you want to keep these devDependencies, skip the pruning step by:
- Setting environment variable
NODE_ENVto anything other thanproduction. This works for all the package managers. - Setting environment variable
NPM_CONFIG_PRODUCTION=falseif you’re using npm. - Setting environment variable
PNPM_SKIP_PRUNING=trueif you’re using pnpm. - Setting environment variable
YARN_PRODUCTION=falseif you’re using Yarn v1. - Setting environment variable
YARN2_SKIP_PRUNING=trueif you’re using Yarn v2 and above.
Build Scripts
By default, the build script in package.json is used to build the application.
While each package manager supports standard preinstall and postinstall scripts, you can run scripts only before or after other build steps. To run specific actions before or after installing dependencies, use the heroku-prebuild, heroku-postbuild, and heroku-cleanup scripts.
package.json"scripts": {
"heroku-prebuild": "echo This runs before installing dependencies.",
"heroku-postbuild": "echo This runs after installing dependencies, but before pruning and caching dependencies.",
"heroku-cleanup": "echo This runs after pruning and caching dependencies."
}Build Flags
You can set build flags to your build script by setting NODE_BUILD_FLAGS environment variable.
Configure NPM
You can configure npm by:
- Adding a
.npmrcfile in the root directory. - Setting
NPM_CONFIGenvironment variable.npmreads configuration from any environment variables beginning withNPM_CONFIG.
When NPM_CONFIG_PRODUCTION is set to true, npm automatically runs all scripts in a subshell where NODE_ENV is production.
Using Private Packages
You can use private packages with npm by configuring the private registry and access token. If the app uses a private dependency source, such a Gemfury, the project must configure an alternate registry with access tokens.
You can specify registry URL and authorization token in .npmrc, like this:
.npmrc@scope:registry=https://registry.npmjs.org
//registry.npmjs.org/:_authToken=${NPM_TOKEN}In this example, NPM_TOKEN is provided as environment variable.
Listening on PORT
Your application must listen on the port specified by the PORT environment variable. App Platform sets this variable at runtime. Here’s an example with Node and Express that uses the PORT variable or 3000 for developing locally.
const express = require('express');
const app = express();
// get our port
const port = process.env.PORT || 3000;
// application code goes here
// have node listen on our port
app.listen(port, () => console.log(`App listening on port ${port}!`));Using Cache
It maintains a build cache that stores caches for npm, yarn, and bower that persists between builds.
You can disable all caching by setting NODE_MODULES_CACHE=false environment variable.
Custom Caching
The node_modules and bower_components are cached by default.
You can override these defaults by setting cacheDirectories array in package.json.
"cacheDirectories": ["client/node_modules", "server/node_modules", "data"]Clearing the Cache
If your app is failing to build and you suspect that the issue is related to node_modules caching, you can force clear the cache and start a new build.
To force clear the cache and rebuild using the Control Panel, go to the Apps page and select your app. Click the Actions menu, then select Force rebuild and deploy.
In the Restart or deploy window, select the Clear build cache option, then click Force rebuild and deploy. This clears the build cache and starts a new deployment.