Day Log App in Node.js Part 7: Deploy in Heroku

This article will discuss how to deploy our node.js Day Log App to Heroku. There are available instructions online to perform this but I faced certain problems that were not in a singular post so I decided to document my entire flow here.

Table of Contents

Steps

Most of the steps here were just taken from the official Heroku Node.js deployment post. I added the logs (if there were) for reference.

Optional

I mentioned in a previous Heroku deployment article that I use a different branch apart from the master to separate Heroku-related configuration changes from the actual code base.

Declare Node.js version

Heroku requires the version of Node.js where the application was built on. Just type node -v in the console (v6.4.0 in my case).

Add it in the project’s package.json:

"engines": {
  "node": "6.4.0"
},

Set PORT to Heroku default

During deployment the application did not run and from the Heroku logs I got the following message:

Error R10 (Boot timeout) -> Web process failed to bind to $PORT within 60 seconds of launch

To solve, I changed 3000 to 5000.

Add Procfile

Heroku uses a Procfile and for my configuration I used the following:

worker: node app.js

Unfortunately the suggested form below did not work for me and only returned an error.

node: web app.js

Create the application

The format to create a Heroku application in the CLI is heroku create. -a <app-name> is added if you do not want Heroku to randomly assign an application name.

$ heroku create -a daylogapp-node
Creating ⬢ daylogapp-node... done
https://daylogapp-node.herokuapp.com/ | https://git.heroku.com/daylogapp-node.git

Add mongolab add-on

Since this application uses MongoDB and mongoose, an add-on for this is needed. I will defer the steps to external sources because it is simple enough to follow.

$  heroku addons:create mongolab
Creating mongolab on ⬢ daylogapp-node... free
Welcome to mLab.  Your new subscription is being created and will be available shortly.  Please consult the mLab Add-on Admin UI to check on its progress.
Created your-new-mongolab-uri as MONGODB_URI
Use heroku addons:docs mongolab to view documentation

After a successful creation, visit your project’s “Overview” page and click the “mLab MongoDB” entry in the “Installed add-ons” section to view the MongoLab page for it.

Heroku - project page - Overview tab

The database URL will be available there and copy it to the definitions in constants.js:

DATABASE: {
    production: process.env.MONGOLAB_URI ||
                'mongodb://<db-username>:<db-password>@uniqueurl.mlab.com:port/heroku_url' ||
                'mongodb://localhost/daylogapp',

I added the variable process.env.MONGOLAB_URI as suggested in the official guide. Make sure to replace the variables db-username and db-password.

Deploy

First, push all changes to your repository and use the command git push heroku master to start deployment.

$ git push origin deploy
Counting objects: 14, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (12/12), done.
Writing objects: 100% (14/14), 1.41 KiB | 0 bytes/s, done.
Total 14 (delta 7), reused 0 (delta 0)
remote:
remote: Create pull request for deploy:
remote:   https://bitbucket.org/giltroymeren/daylogapp-node/pull-requests/new?source=deploy&t=1
remote:
To https://giltroymeren@bitbucket.org/giltroymeren/daylogapp-node.git
 * [new branch]      deploy -> deploy
Giltroys-MacBook-Pro:daylogapp-node giltroymeren$ git push heroku master
Counting objects: 164, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (138/138), done.
Writing objects: 100% (164/164), 22.22 KiB | 0 bytes/s, done.
Total 164 (delta 59), reused 0 (delta 0)
remote: Compressing source files... done.
remote: Building source:
remote:
remote: -----> Node.js app detected
remote:
remote: -----> Creating runtime environment
remote:
remote:        NPM_CONFIG_LOGLEVEL=error
remote:        NPM_CONFIG_PRODUCTION=true
remote:        NODE_VERBOSE=false
remote:        NODE_ENV=production
remote:        NODE_MODULES_CACHE=true
remote:
remote: -----> Installing binaries
remote:        engines.node (package.json):  unspecified
remote:        engines.npm (package.json):   unspecified (use default)
remote:
remote:        Resolving node version 6.x via semver.io...
remote:        Downloading and installing node 6.10.3...
remote:        Using default npm version: 3.10.10
remote:
remote: -----> Restoring cache
remote:        Skipping cache restore (new runtime signature)
remote:
remote: -----> Building dependencies
remote:        Installing node modules (package.json)
remote:        daylogapp-node@0.0.0 /tmp/build_36e0eb912d737ac3e2bf1feb887cfc49
remote:        ├─┬ body-parser@1.17.1
remote:        │ ├── bytes@2.4.0
remote:        │ ├── content-type@1.0.2
remote:        │ ├── debug@2.6.1
remote:        │ ├── depd@1.1.0
remote:        │ ├─┬ http-errors@1.6.1
remote:        │ │ └── inherits@2.0.3
remote:        │ ├── iconv-lite@0.4.15
remote:        │ ├─┬ on-finished@2.3.0
remote:        │ │ └── ee-first@1.1.1
remote:        │ ├── qs@6.4.0
remote:        │ ├─┬ raw-body@2.2.0
remote:        │ │ └── unpipe@1.0.0
remote:        │ └─┬ type-is@1.6.15
remote:        │   ├── media-typer@0.3.0
remote:        │   └─┬ mime-types@2.1.15
remote:        │     └── mime-db@1.27.0
remote:        ├─┬ cookie-parser@1.4.3
remote:        │ ├── cookie@0.3.1
remote:        │ └── cookie-signature@1.0.6
remote:        ├─┬ debug@2.6.6
remote:        │ └── ms@0.7.3
remote:        ├── ejs@2.5.6
remote:        ├─┬ express@4.15.2
remote:        │ ├─┬ accepts@1.3.3
remote:        │ │ └── negotiator@0.6.1
remote:        │ ├── array-flatten@1.1.1
remote:        │ ├── content-disposition@0.5.2
remote:        │ ├── debug@2.6.1
remote:        │ ├── encodeurl@1.0.1
remote:        │ ├── escape-html@1.0.3
remote:        │ ├── etag@1.8.0
remote:        │ ├─┬ finalhandler@1.0.2
remote:        │ │ └─┬ debug@2.6.4
remote:        │ │   └── ms@0.7.3
remote:        │ ├── fresh@0.5.0
remote:        │ ├── merge-descriptors@1.0.1
remote:        │ ├── methods@1.1.2
remote:        │ ├── parseurl@1.3.1
remote:        │ ├── path-to-regexp@0.1.7
remote:        │ ├─┬ proxy-addr@1.1.4
remote:        │ │ ├── forwarded@0.1.0
remote:        │ │ └── ipaddr.js@1.3.0
remote:        │ ├── range-parser@1.2.0
remote:        │ ├─┬ send@0.15.1
remote:        │ │ ├── debug@2.6.1
remote:        │ │ ├── destroy@1.0.4
remote:        │ │ └── mime@1.3.4
remote:        │ ├── serve-static@1.12.1
remote:        │ ├── setprototypeof@1.0.3
remote:        │ ├── statuses@1.3.1
remote:        │ ├── utils-merge@1.0.0
remote:        │ └── vary@1.1.1
remote:        ├─┬ express-validator@3.2.0
remote:        │ ├── @types/bluebird@3.0.37
remote:        │ ├─┬ @types/express@4.0.35
remote:        │ │ ├─┬ @types/express-serve-static-core@4.0.44
remote:        │ │ │ └── @types/node@7.0.15
remote:        │ │ └─┬ @types/serve-static@1.7.31
remote:        │ │   └── @types/mime@0.0.29
remote:        │ ├── bluebird@3.5.0
remote:        │ ├── lodash@4.17.4
remote:        │ └── validator@6.2.1
remote:        ├─┬ jade@1.11.0
remote:        │ ├── character-parser@1.2.1
remote:        │ ├─┬ clean-css@3.4.25
remote:        │ │ ├─┬ commander@2.8.1
remote:        │ │ │ └── graceful-readlink@1.0.1
remote:        │ │ └─┬ source-map@0.4.4
remote:        │ │   └── amdefine@1.0.1
remote:        │ ├── commander@2.6.0
remote:        │ ├─┬ constantinople@3.0.2
remote:        │ │ └── acorn@2.7.0
remote:        │ ├─┬ jstransformer@0.0.2
remote:        │ │ ├── is-promise@2.1.0
remote:        │ │ └─┬ promise@6.1.0
remote:        │ │   └── asap@1.0.0
remote:        │ ├─┬ mkdirp@0.5.1
remote:        │ │ └── minimist@0.0.8
remote:        │ ├─┬ transformers@2.1.0
remote:        │ │ ├─┬ css@1.0.8
remote:        │ │ │ ├── css-parse@1.0.4
remote:        │ │ │ └── css-stringify@1.0.5
remote:        │ │ ├─┬ promise@2.0.0
remote:        │ │ │ └── is-promise@1.0.1
remote:        │ │ └─┬ uglify-js@2.2.5
remote:        │ │   ├─┬ optimist@0.3.7
remote:        │ │   │ └── wordwrap@0.0.3
remote:        │ │   └── source-map@0.1.43
remote:        │ ├─┬ uglify-js@2.8.22
remote:        │ │ ├── source-map@0.5.6
remote:        │ │ ├── uglify-to-browserify@1.0.2
remote:        │ │ └─┬ yargs@3.10.0
remote:        │ │   ├── camelcase@1.2.1
remote:        │ │   ├─┬ cliui@2.1.0
remote:        │ │   │ ├─┬ center-align@0.1.3
remote:        │ │   │ │ ├─┬ align-text@0.1.4
remote:        │ │   │ │ │ ├─┬ kind-of@3.2.0
remote:        │ │   │ │ │ │ └── is-buffer@1.1.5
remote:        │ │   │ │ │ ├── longest@1.0.1
remote:        │ │   │ │ │ └── repeat-string@1.6.1
remote:        │ │   │ │ └── lazy-cache@1.0.4
remote:        │ │   │ ├── right-align@0.1.3
remote:        │ │   │ └── wordwrap@0.0.2
remote:        │ │   ├── decamelize@1.2.0
remote:        │ │   └── window-size@0.1.0
remote:        │ ├── void-elements@2.0.1
remote:        │ └─┬ with@4.0.3
remote:        │   ├── acorn@1.2.2
remote:        │   └── acorn-globals@1.0.9
remote:        ├─┬ method-override@2.3.8
remote:        │ └── debug@2.6.3
remote:        ├─┬ mongoose@4.9.7
remote:        │ ├── async@2.1.4
remote:        │ ├── bson@1.0.4
remote:        │ ├── hooks-fixed@2.0.0
remote:        │ ├── kareem@1.4.1
remote:        │ ├─┬ mongodb@2.2.26
remote:        │ │ ├── es6-promise@3.2.1
remote:        │ │ ├─┬ mongodb-core@2.1.10
remote:        │ │ │ └─┬ require_optional@1.0.0
remote:        │ │ │   ├── resolve-from@2.0.0
remote:        │ │ │   └── semver@5.3.0
remote:        │ │ └─┬ readable-stream@2.2.7
remote:        │ │   ├── buffer-shims@1.0.0
remote:        │ │   ├── core-util-is@1.0.2
remote:        │ │   ├── isarray@1.0.0
remote:        │ │   ├── process-nextick-args@1.0.7
remote:        │ │   ├── string_decoder@1.0.0
remote:        │ │   └── util-deprecate@1.0.2
remote:        │ ├── mpath@0.2.1
remote:        │ ├── mpromise@0.5.5
remote:        │ ├─┬ mquery@2.3.0
remote:        │ │ ├── bluebird@2.10.2
remote:        │ │ ├─┬ debug@2.2.0
remote:        │ │ │ └── ms@0.7.1
remote:        │ │ └── sliced@0.0.5
remote:        │ ├── ms@0.7.2
remote:        │ ├── muri@1.2.1
remote:        │ ├── regexp-clone@0.0.1
remote:        │ └── sliced@1.0.1
remote:        ├─┬ morgan@1.8.1
remote:        │ ├── basic-auth@1.1.0
remote:        │ ├── debug@2.6.1
remote:        │ └── on-headers@1.0.1
remote:        └─┬ serve-favicon@2.4.2
remote:        └── ms@1.0.0
remote:
remote:
remote: -----> Caching build
remote:        Clearing previous node cache
remote:        Saving 2 cacheDirectories (default):
remote:        - node_modules
remote:        - bower_components (nothing to cache)
remote:
remote: -----> Build succeeded!
remote: -----> Discovering process types
remote:        Procfile declares types     -> (none)
remote:        Default types for buildpack -> web
remote:
remote: -----> Compressing...
remote:        Done: 16.7M
remote: -----> Launching...
remote:        Released v4
remote:        https://daylogapp-node.herokuapp.com/ deployed to Heroku
remote:
remote: Verifying deploy... done.
To https://git.heroku.com/daylogapp-node.git
 * [new branch]      master -> master

Check if working

Visit the URL provided in the logs, visit app-name.herokuapp.com, or type heroku open in the console to make sure everything works as intended with the following page at the start:

DayLogApp Node.js index page

This application is available at https://daylogapp-node.herokuapp.com/.

Update files in Heroku master branch

After the initial push to the Heroku master branch there will be a need to update the files. Sometimes if we try the same command git push heroku master we will get the message:

Everything up-to-date

This is not what we should expect - must be git push logs.

Use the following instead to force delivery of changes:

git push heroku HEAD:master

References

Twitter, LinkedIn