The Incomplete Collection of
Node.js Performance Tips

Bookmark and ♥ for later reading :)

Matthias Gattermeier
Node and Beyond
6 min readAug 29, 2015

--

This is a (non-comprehensive) collection of practical advice on how to get more performance out of your Node.js application. While the points I am making below are just some of the more obvious performance boosting tips, I will try to keep a more detailed list maintained on GitHub (if people like it). But let’s jump right into it:

Take Advantage of Multi-Core CPUs with Node Clusters

Node.js is single threaded (duh). So an instance of Node runs in a single thread, not taking any advantage of modern multi-core CPUs. Luckily, Node’s cluster module allows you to easily launch a whole cluster of Node child processes to better handle the load. (And child processes share the same server ports.)

Node’s documentation gives an excellent and easy to read starting point on how to get started with clusters: https://nodejs.org/api/cluster.html

Beyond better performance, clusters will have the added benefit of improving the resilience of your application. The ‘master’ process knows when a child processes crashes, and routes traffic to other child processes until the crashed process gets restarted.

Express Optimizations

Use compression

An often overlooked or forgotten middleware you can use with express is compression. It uses gzip to compress your http payload sent to the client.

var app = require('express')();
var compression = require('compression');
app.use(compression());

Make sure that you load compression before any other middleware.

Use cache

Unlike most server-based applications, Node.js apps will often be designed to run permanently. If that is the case for you, consider setting your most used variables & objects just once at initialization and keep reusing them for any incoming requests down the line. Think of something like “the top 5 articles of the week” your users will see on your frontpage.
Do you really need to update that content every time a user visits your page? If not, you can cache it:

app.set('view cache', true);

Remove unused middleware

Do you make use of http PUT/DELETE requests? If not, disable methodOverride. If you don’t even use POST requests (maybe your app does everything via sockets) you can even get rid of the bodyParser too.

Take a close look which middleware you actually need, and which you can work without of.

And some middleware might only be needed in a specific environment mode. For those cases you can do something like this:

if (app.get('env') !== 'production') {
app.use(morgan);
}

Let’s talk sessions

Express sessions are saved in memory. Your memory footprint grows with every additional user connected. This can add quite a bit of overhead to your application.

Try to limit your use of session variables. Better to use hashed tokens and fetch user data from an alternative session store such as MongoDB or Redis.

But if you are brave enough you might even want to consider to not store any state server-side at all, but dive into client side sessions. For that, take a look at this: https://github.com/mozilla/node-client-sessions

Go Asynchronous

Async code execution

Probably the single biggest advantage of Node.js (besides server side javascript execution itself of course) is it’s asynchronous nature.

Being single-threaded, your Node.js application can easily get blocked by synchronous code execution taking too long to return. If incoming requests can’t get processed anymore, your application is rendered de-facto useless.

Think about some especially time, memory, or CPU intensive tasks. For instance accessing, reading or writing large files. If there is no absolutely, critical, unavoidable reason, you should always use async over sync.

But keep asynchronous support also in mind when choosing external libraries and components. Make sure they are not potentially blocking your application.

Parallel code execution

Revisit your codebase and find chained async callbacks and think if you can run those functions parallel. For instance: You need to read 2 files before executing a callback. This can be done way better than chaining callbacks.

The async module allows you to run functions parallel without the need of chaining them in callbacks. Here the code example for async.parallel:

async.parallel([
function(){ ... },
function(){ ... }
], callback);

Awesome, right? You get one callback executed after all parallel running functions finished. Take a look at the documentation for more details: https://github.com/caolan/async

Bluebird and Q are known first and foremost for giving us promises. But they also let us execute code parallel returning a promise (um.. callback-ish) after all promises (um .. promisified functions) returned.
Let’s look at an example for bluebird:

Bluebird.all([promiseFunction1,promiseFunction2]) 
.then(function(data) {
// will execute after all promisified functions returned
});

ES 6 has a native support for promises and likewise provide a .all() method. Depending on your Node version, you might have already support for it.

Promise.all([promiseFunction1, promiseFunction1])
.then(function(data) {
// will execute after all promisified functions returned
});

If for whatever reason you do not want to use any of the options above, you could also use following approach. But this does not scale well for obvious reasons. Really, you shouldn't do that.

Use V8 native functions instead of adding external libraries

If you come from a traditional web development side to Node.js, you are probably used to working with libraries such as underscore or lodash to take advantage of higher order functions (think of _.each, _.map, etc..)

Those libraries are written with the front-end in mind, and that means they include a sizable chunk of code that makes sure everything works as it should in a variety of browser environment: From Chrome to Safari, from Firefox to IE, plus .. polyfills (Yeah, we are looking at you IE).

Which is great, but also means those libraries contain a lot of additional code that you do not need — not server-side anyways. So before adding yet another module and adding to your resource footprint, try taking advantage of V8 native functions instead, such as forEach, map, etc.

Database Optimizations: Limit query scope and index your collections

If you are working with MongoDB as your database of choice, I have two easy recommendations that could improve your performance quite a bit. (And you should be able to fairly easy retrofit your already existing apps)

  1. limit queries in ‘scope’ whenever possible, and
  2. add indices to collections which are queried often

Imagine you want to display the last 10 posts of a user whenever the user visits your site. First, it is obvious that will want to index your collections accordingly, but you should also make sure to limit your MongoDB queries in ‘scope’. This can mean 2 things: First, to limit the fields you want returned, and secondly (maybe more importantly) to limit the number of documents returned. Take a look at these example snippets from the MongoDB documentation:

db.user.find({ type: 'customer' }, { item: 10, qty: 1 } );db.user.find({ type: 'customer' }).limit(10);

Makes sense? Also dig into the MongoDB’s documentation on creating and working with indices in Node: http://docs.mongodb.org/getting-started/node/indexes/

Btw: I highly recommend Mongo University’s course: “MongoDB for Node.js Developers” Believe me, it’s super awesome!

Client side rendering!

Instead of using server side rendering such Express’ Jade templating, move to client side rendering using React, AngularJS or Backbone.js and have the server provide only the dynamic content really needed. ‘Outsourcing’ rendering to the client can seriously improve your application’s performance.

Don’t use Node.js for static assets

Wherever possible you should avoid using Node.js for serving your static assets. Those include anything from Images, Videos or CSS files.

To improve both, performance of your application and client latency, I recommend a combination of a separate standard web server, such as Nginx, plus taking advantage of Content Delivery Networks (CDNs) to cache and provide those static assets as close to the user as possible.

Personally I have had excellent experiences with Rackspace for both.
Check them out:
www.rackspace.com

Make it ugly!

There is a lot to be said for the beauty of clean code following fancy style guides. But there is more to be said for reducing load and latency — at least in production.

Make it a habit to use Gulp or Grunt to run tasks to uglify your javascript and purify your CSS for your client side code. I personally am becoming a bit of a fan of webpack to bundle everything together as well: http://webpack.github.io/

Use performance monitoring tools to identify bottle necks

This is quite new territory for me, but it is probably fair to say that it’s a good idea to keep close look at your application’s performance during development. I haven't tested them all, (though I made good experiences with New Relic) but here the recommendations I got from others:

Sidenote: Node.js applications in production mode run with higher performance than in development. You can run your app in production mode to get a sense of the performance once your application is deployed.

If you found this post in any way useful, please leave a ♥ .

Thanks :)

--

--