While working on this blog, I could enjoy the ease of file-based routing. It’s just one of the great things about Astro. But during my commute today, I was wondering, how is it achieved? How does Astro or any other framework that supports file-based routing like Next.js know, what the correct pages are and when to serve a 404 page?
So I did what every curious minded person would do: I took my phone and searched. A quick google did not really help, which did surprise me. Therefore I took a different route. I looked at the repos.
fs
and parsing
Broken down to its smallest parts, it could be described as a simple interaction of reading a directory with fs
and parsing the URL to get to the correct file.
Why does this work? Well, for file-based routing to work devs have to put the files into the correct directories (src/pages
in the case of Astro, app
or pages
for Next.js depending on if you want to use SSR and RSC). Inside these directories, the underlying functions look for the correct files (or file endings to be precise) and serve them to the browser.
In the case of Astro
you can add .astro
or .md
(and every other markdown related ending) files to the pages
directory and it will work.
For Next.js
, it depends on the router you use: if you use the pages
router, it works with <filename>.jsx
or <filename>.tsx
. With the app
router, you have to use page.tsx
(or .jsx) and subdirectories.
The URL is parsed in some way: <domain>/
will receive the index.astro
file (or the index.tsx
or app/page.tsx
in Next). <domain>/about
will get the about.astro
file. Things get a bit more complicated for URLs like <domain>/tags/web-dev
where you could find this post.
Serving subdirectories
For these situations, it’s necessary to put the files in a directory inside the pages
directory (don’t worry, I will talk about the Next appDir further down below), like pages/tags/index.astro
. Both Astro and Next use specific function that parse the URL to match the filePath.
The following is the actual function used for the pages directory in Next.js (as of today, and yes I am aware that this function is used in the ESLint plugin):
Let’s break this down:
- the first step is to read the given directory with
fs
with the fileTypes- the fileTypes are necessary to check if the entry of the directory is a directory itself or a symlink
- the next step is to check if the files end in
.tsx
or.jsx
- if this is the case, the file name is checked: if it’s
index
, the name is stripped, otherwise it is kept - the saved route is then the
urlprefix
+ the filename
- if this is the case, the file name is checked: if it’s
- if the entry is a directory, but no symlink, the function is called recursively with an updated
urlprefix
- the original
urlprefix
is/
- the original
- after the recursion, an array of strings is returned
The parsing of the Astro URLs is pretty similar, so I won’t describe this here.
The appDir
With Next.js 13 came a new paradigm: server side rendering (SSR) and react server components (RSC). This resulted in a new file structure: the file that is exposed to the browser is called page.tsx
(or jsx), while other files are used for different use cases (layout.tsx
for the layout, route.ts
for API endpoints). So, about.tsx
would not work.
This results in a greater emphasis on the subdirectories: app/about/page.tsx
is now the same as pages/about.tsx
and will result in <domain>/about
.
The function for the app directory is pretty much the same, but it checks for page.tsx
files - which makes sense since this is the only file that will get to the browser.
Dynamic routes
I have talked a lot about Next now, let’s get back to Astro for this one.
Dynamic routes allow you to create flexible routes that can match a variety of URL segments, making it easy to handle parameters and generate dynamic content. In Astro, all routes must be determined at build time, so it’s necessary to generate the static paths with the getStaticPaths()
function. Here, you define every possible route.
I did the following for this blog:
I get all entries in the blogs
collection that are not drafts. The slug of the filename is now a route. But since pagination is also possible, the number of the possible pages should also be added as a path.
With this function, the possible paths grow automatically if I create a new post. Neat!
Conclusion
Whether you choose Next.js or Astro (or any other framework that supports file-based routing), both frameworks provide powerful tools for file-based routing, enabling you to build dynamic and performant web applications with ease.
File-based routing isn’t just a convenience; it’s a fundamental concept that empowers developers to build web applications that are not only developer-friendly but also user-friendly.