My beef with Next.js's file-based routing

Table of contents

As someone who has mostly worked with Next.js up until 3 weeks ago, I have gradually moved from really liking file-based routing to having mixed feelings about it, especially since I started working with react-router-v7 3 weeks ago.
What is this all about?
File-based routing does not allow you separately define your components and routes hierarchies, and this becomes a real pain once you have to add new routes in a codebase with deeply nested folders and sharedlayout.tsx
files.
The Next.js strategy
In nextjs, by default, component hierarchy and route hierarchy are tightly coupled to folder hierarchy, a.k.a file-based routing. This means you don't have to manually set up routing; want to add a new route? Just add a new folder in the specific subfolder, give it a `page.tsx` file, and you have a new route. Awesome! No dedicated routing file required!
When I first got started in Next.js, I liked this approach and I still do (for certain use cases). However, once you start working on apps that have deeply nested route hierarchies and shared layout files, file-based routing becomes really painful, really quickly.
Consider that I have the following folder structure
app
|-- blog/
|-- personal/ /blog/personal
|-- collab/ /blog/collab
layout.tsx
In the above folder structure, /blog/personal
and /blog/collab
both share some components via the layout.tsx
file. I intentionally hid the corresponding page.tsx
files as they aren't important for this.
Now, say I need to introduce a third route /blog/company
and for some reason, the page for this new route does not share most of the components inside the shared layout.tsx
file. All of a sudden, I am now forced to rethink the structure of my folders because creating a company/page.tsx
file inside blog/
in it's current form, will include the shared components from the layout.tsx
file into the rendered /blog/company
route and I don't want this.
To solve this problem, I can restructure my folder to look like this, using a route group
app
|-- blog/
|-- (group)
|-- personal/ /blog/personal
|-- collab/ /blog/collab
layout.tsx
|-- company/ /blog/company
Now, the layout.tsx
will only apply to /blog/personal
and /blog/collab
but not to /blog/company
. Problemo solved. This was a simple example, but imagine having to make a change like this in a codebase with folder structure that is deeply nested with multiple levels of shared layout.tsx
files. Yikes!
Now, to React router
In react router, by default, our folder structure does not dictate the route paths, neither does it dictate the component hierarchy. Instead, we explicitly define what component is linked to what route inside the routes.ts
file. Inside the same file, we can also explicitly define our component hierarchy by nesting route()
within route()
and layout()
.
And the best part is that adding a new route, reordering existing routes, or reordering sections of the component hierarchy, does not require reordering our folder structure, and this is cool.
Now, let's see the exact situation we had with Next.js but in react router v7.
// routes.ts
export default [
layout("routes/blog/layout.tsx", [ // shared layout for both /blog/personal and /blog/collab
route("/blog/personal", "routes/blog/personal.tsx") // /blog/personal
route("/blog/collab", "routes/blog/collab.tsx") // /blog/collab
])
]
To add the /blog/component
route, we simply do;
export default [
layout("routes/blog/layout.tsx", [ // layout.tsx shared by /blog/personal and /blog/collab
route("/blog/personal", "routes/blog/personal.tsx") // /blog/personal
route("/blog/collab", "routes/blog/collab.tsx") // /blog/collab
]),
route("/blog/company", "routes/blog/company.tsx") // /blog/company
]
All we needed to do to register this new route was just to declare the route outside the shared layout()
. It was simple.
In conclusion
Despite how this might all sound, I'm not trying to say that file-based routing is inherently bad. In fact, the routes.ts
approach of react-routerv7 has its issues too. One issue that comes to mind is that, since the route hierarchy isn't coupled to folder hierarchy, maintaining a consistent folder structure is now the task of whoever is working on that codebase at any point in time.
If you take anything away from this rant of mine, it should be that every tool/approach has its strengths and weaknesses, and understanding this is key to effectively using that tool/approach for the task at hand.
Subscribe to my newsletter
Read articles from craftzniac directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

craftzniac
craftzniac
Just a guy on an adventure to explore the awesome world of software engineering