How filesystem-based routers work: building one for express
Matteo Gassend
October 22, 2023
import Stackblitz from '../../components/mdx/Stackblitz.astro'
Have you ever wondered how Next, Sveltekit, Nuxt (even Expo now) do their routing? What's the magic that makes it so when you create a file called in a directory called , just for it to magically works? Well, wonder no more! I'll show you how to build your own file-based router for express in Javascript, though the concepts we'll see are usable in other frameworks and other languages. This article will focus on parsing files, ignoring folders (because that is a whole of grenades I'm not yet ready to step - and write - on). Let's get to it!
How file routing works
First, let's start by saying what file-based routing is and how it works.
Usually, a function will loop through the folder (ever noticed how you always have a single place where you place your ? this avoid crawling the whole project directory every time your app starts), getting all the files matching a certain pattern (for svelte, that will be ) and, based on their location in the folder, determines what requests should be sent to it. The first part of this series, as specified above, will not be handling folders; instead, we will just do a basic file router; here's how it'll work:
This means that when we'll call our function, it will step through our route directory and generate a separate route for each filename: will create for example.
Building a file-based router
Initial Setup
First of all, we should setup our base structure. For this example, I'll have an file at the root of my project that will instanciate the express application and call the function to generate the routing. Then I'll have a folder that will contain - you guessed it - our routing files. The only dependency you should need is the package; if you haven't already done so, you should install it in a new project using:
and let's initialize the express application in
This should be enough to have a basic http server listening on port 4000 (btw, you should probably use an environment variable here instead of hardcoding it like this). Next, let's see how we should define our route file; inside our folder, let's create a file; this suffix (.route) allows us to filter only the files we are sure belong to our application thanks to the power of regex (oh yes, we'll be writing a regex - just one, I promise)!
Making a route
Let's start by defining a simple rule: every route file should have a Router instance as its main export. This will allow us to do simple programmatic requires to load our route files (we'll look at how to do more specific filtering and imports in a following article, don't worry).
So, let's say we have a file containing the following:
When our loader will be finished, this should generate two routes:
/user
/user/:id (this one will match /user/1, /user/2 etc)
Making the loader
Now it's time to make the actual loader:
Let's recap what our loader needs to do:
walk the folder
for each file matching the pattern (routeName).route.js, add a route to our express app that looks like
So, i'll make a new file called which exports an asynchronous function. This function will take as an argument the express application and define a regex we will use to match our route name and save it as a group.
And in this function we'll begin by walking the whole folder
And then check each file to see if it matches the regex we defined earlier:
And finally, we add the route to our application with a little log line:
The last step is to use our loader function: your index.js should look something like this:
This is the simplest way to make a file-based router in express js. This logic can obviously be translated to be used in other framework, like this plugin for fastify
You can see a working example below:
Discussion in the ATmosphere