Node.js Buildpack on App Platform

App Platform is a Platform-as-a-Service (PaaS) offering that allows developers to publish code directly to DigitalOcean servers without worrying about the 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.

Node.js Applications using Buildpacks

App Platform looks for any of the following files to detect a Node.js application:

  • package.json
  • package-lock.json
  • yarn.lock
  • pnpm-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 260 of the Heroku Node.js buildpack. The buildpack supports running most Node.js versions 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
    • 21.0.0 - 21.7.3
    • 22.0.0 - 22.5.1

App Platform uses Node.js 20.x by default if you do not specify a Node.js version in the engines section.

Specify a Node.js Engine

You can specify your desired Node.js version in the engines section of 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:

    
        
            
{
  "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:

    
        
            
{
  "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:

    
        
            
{
  "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:

    
        
            
{
  "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:

    
        
            
{
  "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.

Note
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.

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:

    
        
            
services:
  - 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:

    
        
            
services:
  - 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:

    
        
            
services:
  - 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_ENV to anything other than production. This works for all the package managers.
  • Setting environment variable NPM_CONFIG_PRODUCTION=false if you’re using npm.
  • Setting environment variable PNPM_SKIP_PRUNING=true if you’re using pnpm.
  • Setting environment variable YARN_PRODUCTION=false if you’re using Yarn v1.
  • Setting environment variable YARN2_SKIP_PRUNING=true if 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.

    
        
            
"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 .npmrc file in the root directory.
  • Setting NPM_CONFIG environment variable. npm reads configuration from any environment variables beginning with NPM_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:

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

        
    

In this example, NPM_TOKEN is provided as environment variable.

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 do this in the control panel, navigate to your app, click the Actions menu, and then select Force Build and Deploy.

Force Build and Deploy screen with Clear Build Cache checked

In the Force Build and Deploy window, select the Clear Build Cache option, and then click on the Deploy button. This clears the build cache and starts a new deployment.

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}!`));