Filesystem Routers & Indexes
Soon, Next.js will support FS-based routes, like Sapper, Nuxt.js, and my own polydev and mdx-site.
But, there’s one design decision I’ve made that differs from the rest:
all routes are
A lot of engineers work from the bottom up.
“I’ll connect to the DB, query for the data I need, expose it as an API, then wire it up to the HTML.”
But, I’ve found it more intuitive to work from the user down. (Because, ultimately, the implementation details don’t matter).
/some/url, hit an API, then return a query from the DB”.
Maybe we can call this approach
Since Cool URIs don’t change, designing URL structure is good design.
The Filesystem Looks Like a URL
Even when I
git clone a project, I have a habit of making the filesystem look like a URL.
For example, my
~/Projects directory looks like my GitHub repos:
$ tree -L2 . ├── ericclemmons │ ├── mdx-site │ ├── medium-to-markdown │ ├── node-recorder │ ├── polydev │ └── ... ├── webpack-contrib │ └── npm-install-webpack-plugin └── zeit └── next.js
So it makes sense that projects like UmiJS
would find a way to map
/users/:id to the filesystem:
+ pages/ + $post/ - index.js - comments.js + users/ $id.js - index.js
In my projects, however, I whitelist
index.* files for route creation.
Why Indexes Matter
For a small project, this seems fine:
pages/ index.js about.js contact-us.js
But, as complexity grows, you’ll find yourself with an underscore smell:
pages/ _app.js _document.js _layout.js _fetchFromDB.js ... index.js about.js contact-us.js
Because every file under
pages/ automatically becomes a page,
we have to find ways to get these files blacklisted.
When designing URL structure upfront, a whitelist allows our app to grow without side-effects.
For comparison, my suggested structure is:
pages/ index.js about/ index.js contact-us/ index.js
Benefits to Index-based Routes
about/index.htmlis well-suppored by many static servers at the URL
index.jscan be called whatever you’d like, without accidentally generating new pages for each file.
Customizing the extension allows for more functionality in the future:
post/:id/index.POST.jscould handle updating
post/:id/index.*.jscould be a fallback for
/post/123/*& show a custom
Of course, what people choose for denoting parameters (e.g.
has to be a valid filename,
but the most important goal is to provide an quick, intuitive path from the URL in the browser to the file serving it.