Troubleshooting Node.js Deploys
Last updated October 31, 2023
Table of Contents
Your Node.js deploy failed, now what? Start with these steps to troubleshoot a build issue.
Check the Buildpack
Is the app using the officially supported and maintained buildpack? Most of the time, the standard buildpack is the best choice, either alone or paired with other buildpacks, such as the Heroku Ruby Buildpack.
To find out, run:
$ heroku buildpacks
To use the official buildpack, run:
$ heroku buildpacks:set heroku/nodejs
Compare Node and NPM Versions
You want the production environment to mirror the app’s development environment as closely as possible. Being a few patch versions off is okay. First, check local versions.
$ node --version
$ npm --version
Then compare the results with the
engines section in your
package.json. Make sure that a Node version is specified.
Heroku outputs which binaries (ie.
npm) are used for each deploy in the build logs.
remote: -----> Installing binaries
remote: Resolving node version 20.x...
remote: Downloading and installing node 20.9.0...
remote: Using default npm version: 10.1.0
If the binaries don’t match up with the same local versions, specify the matching versions in
Make Sure That the Lockfile Is Up to Date
If a lockfile is present and checked into the app’s repository, such as
yarn.lock, make sure that the it’s up to date and checked into Git.
We recommend using a lockfile when the
package.json references third-party dependencies.
To update the
npm install, and then check the changes into Git.
To update the
yarn.lock file, run
yarn install, and then check the changes into Git.
Don’t Check In Generated Directories
node_modules directory is generated at build time from the dependencies listed in
package.json and the lockfile.
node_modules and other generated directories like
bower_components don’t belong in source control. Check with:
$ git ls-files | grep node_modules
If you get results, instruct Git to stop tracking
$ echo "node_modules" >> .gitignore
$ git rm -r --cached node_modules
$ git commit -am 'untracked node_modules'
Check for Differences Between Development and Production
Many Node applications have checks that perform different logic based on the value of the
NODE_ENV environment variable. These checks are especially common when, for example, building web assets and compressing images during development.
Occasionally, checks can lead to subtle bugs that only show up when trying to deploy. If a new bug appears while deploying, check to see if you can reproduce it locally by setting
$ NODE_ENV=production npm start
A required file can exist locally, but it’s possible that an overly broad rule in
.gitignore accidentally blocks it from inclusion in the app’s Git repo.
As an example, sometimes it’s best to exclude a
lib directory at the root of your application, but with:
Git recursively matches any subdirectory named
lib, so the file
js/library-name/lib/index.js isn’t included in the Git repo. Fix this case by moving the slash to the front, which only matches the
lib directory in the application root directory.
Open a Ticket
If none of these solutions work to fix the app in question, open a ticket with Heroku so we can help.
AWS Proxy Error
If builds aren’t completing with an error when downloading Node, sometimes there’s an issue downloading binaries. The build error can look like:
-----> Installing binaries
engines.node (package.json): 10
engines.npm (package.json): unspecified (use default)
Resolving node version 10...
Error: Unknown error installing "10" of node
Or the error can mention:
-----> Node.js app detected
curl: (35) OpenSSL SSL_connect: SSL_ERROR_SYSCALL in connection to lang-common.s3.amazonaws.com:443
HTTPS_PROXY environment variables in the app’s build cause these types of failures. If the build or app doesn’t need
HTTPS_PROXY environment variables, we recommend removing the variables from the app’s environment.
$ heroku config:unset HTTP_PROXY HTTPS_PROXY
If the build environment requires a proxy for HTTP or HTTPS connections, set the
NO_PROXY environment variable to
amazonaws.com before you execute the process. Another option is to set the config var:
$ heroku config:set NO_PROXY=amazonaws.com
If a module included in the
package.json is missing from the build or the production app, it’s possible that Heroku removed it during pruning. A common error looks something like:
Error: Cannot find module 'express'
To create a smaller slug size for apps, the buildpack prunes out the
devDependencies from the
package.json at the end of the build so that the slug only includes the
dependencies listed at runtime. If there’s a required dependency in the
devDependencies after the prune occurs, move the dependency to
dependencies so that the buildpack doesn’t remove it.
The other solution is to turn off pruning of
devDependencies altogether by setting a config var:
$ heroku config:set NPM_CONFIG_PRODUCTION=false
If the app uses Yarn, run:
$ heroku config:set YARN_PRODUCTION=false
For more information about configuration package installations, visit the Node.js Support docs.
Incorrect Port Setup
Heroku apps don’t bind to just any port that your app is set up with. Apps use the Node
process to bind to a port.
When set up incorrectly, your app deploys successfully, but it crashes repeatedly. You can see an error like this one in your logs.
heroku[router]: at=error code=H10 desc="App crashed" method=GET path="/" status=503 bytes= protocol=https
To fix this issues, use the
process.env.PORT variable to bind your web server to the port. If you use port 3000 for your local development, your code looks something like:
app.listen(process.env.PORT || 3000);
The Node process takes the
PORT environment variable that Heroku set in your app.
Install and Build Script Failures
Sometimes installing a dependency or running a build locally completes successfully, but when it gets to Heroku, the build fails. If you run into an issue where a dependency only fails on Heroku, we recommend spinning up a one-off dyno to debug the script. The dyno is created from the slug of the most recent deploy, so try to get the build to pass in order to debug in a Heroku environment. You can make the build pass by uninstalling the troublesome dependency, removing the build script from the
package.json, or making other modifications to the code.
After you deploy the code to a staging app, create the one-off dyno.
heroku run bash -a example-app
Running bash on ⬢ example-app... up, run.2524 (Basic)
After the dyno has spun up, you can poke around and run scripts to debug. Install dependencies as needed.
$ npm install debug
up to date, audited 52 packages in 2s
found 0 vulnerabilities
package.json, you see that
debug installed. You can also have a failing build script, but you can run it manually with the
$ npm run build-production --verbose