Troubleshooting Node.js Deploys
Last updated 15 November 2017
Table of Contents
Your Node.js deploy failed - now what? Start with these simple steps to troubleshoot a build issue.
Check your buildpack
Are you using the officially supported and maintained buildpack, or something else? Most of the time, the standard buildpack is the best choice - either alone, or paired with other buildpacks (like Ruby).
Find out by running:
$ heroku buildpacks
To use the official buildpack:
$ heroku buildpacks:set heroku/nodejs
Compare Node and npm Versions
Your production environment should mirror your development environment, especially in the case of important binaries. First, check your local versions:
$ node --version $ npm --version
Then, compare the results with your
engines section. You are specifying a node version, right?
You can see which binaries Heroku is using on each deploy in the build logs, which look something like this:
remote: -----> Installing binaries remote: Resolving node version 0.10.x via semver.io... remote: Downloading and installing node 0.10.35... remote: Using default npm version: 1.4.28
They should match up with the same versions you saw locally. If they don’t, you should specify the matching versions in your
Don’t check in generated directories
node_modules directory is generated at build time from the dependencies listed in
node_modules (and other generated directories like
bower_components) shouldn’t be included in source control. It’s easy to check:
$ git ls-files | grep node_modules
If you see a list of results, then you should instruct git to stop tracking
$ echo "node_modules" >> .gitignore $ git rm -r --cached node_modules $ git commit -am 'untracked node_modules'
Instead of committing
node_modules directly into your repository, you can ensure exact versions via npm’s shrinkwrap or by using the
$ npm install express --save --save-exact
Ensure you aren’t relying on untracked dependencies
npm install a module, that module is saved to your project’s
node_modules directory but not to the package.json file that describes your project’s dependencies. This means that your project will work on your machine, but as soon as you try to share it elsewhere it will fail with missing dependencies.
Instead, install locally with
npm install --save foobar. That will automatically record the installation to your
package.json dependencies list.
For the same reason, you should avoid installing global dependencies (
npm install -g foobar). Use
--save instead to put binaries in
myproject/node_modules/.bin, keeping them local and trackable.
If you run binaries (like grunt or bower) from an npm script, the
node_modules/.bin directory is automatically added to the
path, so you don’t need to include it in your script.
Here’s how to check whether or not you’re relying on commonly-installed global modules:
$ which bower $ which grunt $ which gulp
If any of these show a path, your project may depend on a binary outside of its local directory, leading to a case of, “but it works on my machine!”
Remember: the grunt command line is actually installed via
npm install --save grunt-cli
If you’ve added these modules to package.json, but they still aren’t installing, be sure that you’ve added them to the correct list. In Production (
NPM_CONFIG_PRODUCTION=true), ‘devDependencies’ won’t be installed, so anything you need in production should be moved to 'dependencies,’ or production mode should be disabled:
$ heroku config:set NPM_CONFIG_PRODUCTION=false
For a full example, check out Building Node.js Apps with Grunt.
Start with a blank slate
Each time you run
npm install, npm leaves packages that meet your semver requirements untouched. That’s why an
npm install today may lead to a different tree than the
npm install you ran yesterday, even if your
package.json didn’t change.
Therefore, it’s a good practice to periodically clear
node_modules and reinstall from scratch to ensure that your
package.json dependencies are still valid:
$ rm -rf node_modules $ npm install --quiet --production $ npm start
In fact, those are essentially the commands that Heroku runs when we build and launch your project. If they work locally, you’re likely to be cloud-ready.
Alternatively, you can add yarn or npm-shrinkwrap to your workflow to lock down dependency versions so that they are consistent from install to install. This is the best practice for production environments.
Check for differences between development and production
Many Node applications have checks that will perform different logic based on the value of the
Occasionally this can lead to subtle bugs that will only show up when trying to deploy. If you run into a new bug while deploying check to see if it can be reproduced locally by setting
$ NODE_ENV=production npm start
A required file may exist locally, but it’s possible to accidentally prevent it from being included in your git repo by an overly broad rule in your
As an example, you might wish to exclude a
lib directory at the root of your application, but the rule:
.gitignore will recursively match any subdirectory named
lib, so the file
js/library-name/lib/index.js would not be included in your git repo. You can fix this case by moving the slash to the front, which will only match the
lib directory in the application root directory.
Open a ticket
If none of these solutions work for you, open a ticket with Heroku so we can help.