How JSON.stringify killed my express server

Getting up to 300% more performance from an express server with a simple change

Photo by Max Chen on Unsplash

Express is one of the most used node.js frameworks out there when you need to create server.

Here is an example of a simple express server with only one endpoint returning a small static JSON response.

Running the code above and benchmarking it using autocannon for multiple times shows the server, running on a 2018 MacBook pro, handles roughly 190K requests in 11 seconds ~= 1900 RPS

We can do better!

Since there is so little code in this example, there is only one place where we can look for better performance — express source code, the definition of the json function on the response object (full code found at: https://github.com/expressjs/express/blob/master/lib/response.js)

The most important part happens in line 22, stringily — for every res.json that we use, the returned value is stringifed to be sent as an http response. After stringifing the data, the content type is set and response is sent.

JSON.stringify is a cpu bound operation, not node’s best friend, so let’s try and do it only once.

We can stringify the result and save it to variable, and for each incoming request we can set the content-type to application/json and use the end method to write the string directly to the socket:

Running autocannon again gives us around 350K requests in 11 seconds ~= 3500 RPS. 80% improvement.

But wait you say, you promised me 300% improvement !! and you would be right!

The performance difference depends heavily on the object returned. I wanted to show that even a small change on a small object can be significant.

Try doing the same thing with a big json object (like 500–600 Kb), you’ll get your performance boost. Actually, using res.json, might actually causes your server to crash in a limited environment like a container running on kubernetes.

Conclusions

When using express, if your server performs poorly RPS wise, try cache any shared response and write the string directly to the response stream instead of using res.json which uses JSON.stringify everytime.