Skip to content

How does fallthrough work with express.static()?

So, I’ve a basic express setup as shown below:

const path = require("path");
const express = require("express");

const app = express();

app.use(express.static(path.join(__dirname, "public")));

app.get("/", (req, res) => {
  res.send("Home Page");
});

app.get("/about", (req, res) => {
  res.send("About Page");
});

app.listen(3000, () => {
  console.log("Server listening on PORT 3000");
});

In the code above app.use() middleware will be executed for every request because the default path for app.use() is /.

Now express.static() will be serving the public directory, so if I go to / route I will see the contents of the index.html file and the app.get("/") middleware will not get executed.

But when I go to /about, I see the contents sent from app.get("/about"). This is what I don’t understand because according to docs it calls next() only when the file is not found, but when it is found the request stops there.

So, when I navigate to /about, app.use() will be the first to get executed and it will find index.html file and should render that, but instead it calls next and the get handler for about gets executed. WHY?

I am not very clear how static assets are being served, I guess when I go to /about it is not actually looking for index.html file but then what file is it looking for?

Answer

The root argument specifies the root directory from which to serve static assets. The function determines the file to serve by combining req.url with the provided root directory.

So, app.use(express.static(path.join(__dirname, "public"))) serves the public directory.

Visiting / route

Remember the file to serve will be determined by combining req.url with root. So, in this case req.url is / and root is public. So express will try to serve public/index.html, where index.html is the default, if no file is specified explicitly.

Sends the specified directory index file. Set to false to disable directory indexing.

This file will be found and will be rendered and the request ends there, so the get handler for / is not executed.

You can set the index property to false and then express will not look for index.html file by default.

So, setting app.use(express.static(path.join(__dirname, "public"), { index: false })) will make express to not look for index.html file by default and now if you visit / route, the get handler for / will be executed.

Visiting /about route

This time req.url is /about, so express will try to serve public/about/index.html, which will not be found and therefore it calls next() and the get handler for /about gets executed.

Visiting /about.html route

This time req.url is /about.html, so express will try to serve public/about.html which if found will be rendered else next() will be called.