Using Heroku with Node.js: Production-Ready Application Checklist

In this post, I'd like to teach you some of the Heroku best practices we use at RisingStack for going to production with Node.js, and give you a general checklist as well.

You are going to learn how to deploy applications to production, how to do proper logging and monitoring, and how to debug effectively.

These best practices will save you from false alarms waking you up in the nights as well as provide a consistent user experience for your users.

Step #1: Run Your Tests Automatically

All applications - not just Node.js - must have a proper test suite. The test suite functions as a safeguard, so you won't accidentally change the functionality of a given module, or worse, the whole application.

All tests in Node.js should run using the npm test command, so you should define your test commands in your package.json file's scripts section.

{
  "scripts": {
    "test": "NODE_ENV=test mocha --require co-mocha test/setup.js '**/*.spec.js'"
  }
}

Step #2: Do Automatic Deployments

We see lots of manual steps involved in deployment, even in bigger systems. This approach is very error-prone - in case someone forgets something, you will have a bad time. Because of this, you should never do deployment manually.

Instead of that, you can automate the whole process with great tools like Codeship or CircleCI. These tools should run your tests, and if everything is green, it should deploy your software. In CircleCI, we usually set up our tests to run these commands:

test:  
  pre:
    - npm install
  override:
    - npm run lint
    - npm test

Once all the tests are passed, the CI has to deploy our application. But where should it deploy it to?

At RisingStack, we usually have two environments, one called Staging, and one called Production. The CI ships the application to the Staging environment. There is a manual step involved to move the application from Staging to Production. On Heroku, you have the Pipeline feature for this.

Heroku with Node.js - Pipeline View

On the UI with the Promote to production... button, you can simply push your Staging application to Production. These applications share the same codebase but can have different environment variables so that you can connect them to your staging databases.

To read more about how you should structure your applications on Heroku, I'd recommend reading the 12-factor application principles.

Step #3: Set Up Proper Logging

Logging in production is crucial. Logging in Node.js enables you to:

  • have a better understanding of how your applications work,
  • discover what errors you have,
  • find out if your services are running correctly.

Proper logging should always have a

  • timestamp,
  • a format that's easily understandable for humans and machines as well,
  • a log destination, preferably the standard output,
  • support for log levels, so you can dynamically modify what to log.

At RisingStack, we mostly use winston. Winston is a multi-transport async logging library for Node.js.

You can add winston to your project by installing it:

npm install winston --save  

To create your first log line, you can run something like this:

const winston = require('winston')

winston.log('info', 'Hello log files!', {  
  someKey: 'some-value'
})

The output of the snippet above will be:

info: Hello log files! someKey=some-value  

You might notice, that the first argument to the winston.log was info - this is where you can specify the log level of a given log record. You can modify the current log level you use, with assigning the new level to winston.level, like winston.level = 'debug'. By default, winston supports error, warn, info, verbose, debug, and silly levels.

You can set the winston.level from an environment variable, like = winston.level = process.env.LOG_LEVEL, so whenever your application restarts, the new levels will be applied.

If you're looking for great log providers on Heroku, you can start using Logentries, Papertrail or Logz to store and search your logs.

Step #4: Set Up Alerts in Production

Both Logging and Monitoring is a must for production systems - as you have logging in place already, let's take on why you need monitoring and how you can set yours up!

You have an obligation to continuously detect bottlenecks and figure out what slows your product down.

An even greater issue is to handle and preempt downtimes. You must be notified as soon as they happen, preferably before your customers start to complain. Based on these needs, proper monitoring should give you at least the following features and insights into your application's behavior:

  • performance dashboard, to provide a quick overview of the state of your application,
  • monitoring network connections,
  • real-time alerting,
  • code-level insights.

You can install Trace as Heroku addon to solve this task:

Finding the Trace Node.js Heroku Addon

Once you do that, you have to follow the onboarding steps - this shouldn't take more than a couple of minutes.

Heroku Node.js Install Steps for Trace

Step #5: Profile your Production Systems

Profiling on the code level is essential to understand how much time does your functions take to run in the actual production environment. Luckily, Trace covers this area as well.

All you have to do is to head over to the CPU Profiles tab on the Profiling page. Here you can request and download a profile which you can load into the Chrome DevTool as well.

Heroku - Node.js CPU Profiling

Step #6: Find the Memory Leaks

Go to the Profiler page in Trace and request a new memory heap dump, then wait 5 minutes and request another. Download them and open them on Chrome DevTool’s Profiles page. Select the second one (the most recent one), and click Comparison.

Node.js Memory Leak detection in Heroku

Okay, but what does this graph mean?

When you search a memory leak, you have to look for the #Delta column. Click on it, and you will see the number of additional elements in the second memory dump (compared to the first one).

On the bottom of the picture, you can see what these elements were, and you can start figuring out what caused the leak.

Heroku & Node.js = <3

Running a production app on Heroku is quite easy if you follow these best practices. Of course, there's much more to monitoring your applications performance on Heroku; we just got the basics right this time.

If you'd like to get a little bit better with measuring and optimizing your Node apps performance, I recommend to go through these articles: