Don’t serve static files with NodeJS

Many JavaScript rock stars/ninja/hackers using Express — the awesome framework that makes your life easier with a bunch of built-in features.

One of the most popular features is the express.static middleware. We use this to serve static files, with just a single line of code:

app.use('/public', express.static('public'));

By doing this, we all made the biggest mistake!

So, using express.static is completely wrong?

There are nothing wrong with express.static if you use it just for small sites.

But use it all the time without thinking of the pros and cons is completely wrong.

Let’s take a look at this diagram:

This is the typical NodeJS application that uses Express. We have a single process that serving both website contents (HTML, JSON data…) and static files (CSS, JavaScript, Images,…).

And then, the problem came up. As we already know, NodeJS run your code on a single thread, everytime browser send a request, your server will make other requests wait until this request finished.

Let’s say, when user opens your website, browser sends 5 requests to get 5 resources, your server will response one by one, as the image below:

So, let’s imagine, what will happen if Facebook used express.static to serve your photo albums? You have to wait for few minutes to load your photos! What a bad idea!

How do we fix this?

Let’s just get off topic for a while, many of us deploying our NodeJS application on production environment along with nginx!

We end up creating something like this on our servers:

Every request coming to the server will go through nginx before redirected to our NodeJS application. Well… this is just a new kind of waste.

The Express server still serve both static files and website contents at the same time.

To deploy our application in a right way, we will apply one of Unix’s philosophy: Do One Thing and Do It Well!

We will let nginx serve our static files — nginx is good at this. And our Express server just have to serve the website contents.

Serving static files with nginx is very simple, just need to add this snippet in your config file:

location /public/ {
root /var/www/app/;
autoindex off;
}

This will let the static contents in /var/www/app/public folder accessible via HTTP requests.

If you have a NodeJS server running on port 5000 and want to serve static files in nginx, this is the sample config:

server {
location / {
proxy_pass http://localhost:5000;
}
    location /public/ {
root /var/www/app/;
autoindex off;
}
}

This will be our new server setup:

Now we have 2 servers to serve 2 content types. When the requests coming, nginx and Express will serve our resources in parallel!

And hell yeah! The website now load faster!

TL;DR

Just for a quick summary, this is what we talked about:

  • NodeJS run our codes on a single thread
  • Your Express server is actually a code that being executed in that single thread
  • A browser will send multiple requests to Express server to get multiple resources, and those request will be fulfilled one by one, and the loading time for your website will be very slow!!!
  • To fix it, we use nginx to serve static files, and Express just need to serve website contents (Do One Thing and Do It Well)

Hope this post will help you understand how NodeJS’s single-threaded model with event loop architecture affects the web performance, and how can we solve it.

If you have any question or anything to share, just let me know by leaving a comment, we will discuss them in details.

Happy coding ^^

Updated: Thank you so much guys, for pointed out some security issue in the comment! We should be careful with the server config because nginx already running with a difference user than our NodeJS application, so nginx might not able to access the static files (403 — Forbidden Error), and this may lead us to have some insecure configuration like: running nginx with root user.

Update #2: It’s a good idea to serve our static files with a CDN if our web application required a lot of traffic for them.