If you're working on a brand new project from the ground up and it has a server-side component, then you'll have to figure out early on just how you want to organize your files. This is by far, not my favorite step in the development process. And that's because it is a crucial step and if you do it wrong, you're going to be kicking yourself a year from now because you wish you had done it differently.
You'll want to organize everything in a way where it's simple to add new pages, components, functions later on without having to overhaul anything major. And you'll want to take security into account as well, meaning that only the appropriate files that need to be public, should be public.
So the following is a sample folder layout for a Next.js API project that more or less resembles what I would use in a real-world application. I say more or less, because on a production environment I would typically have more security and sanitation related folders and files. But to keep things simple I'll mainly just focus on routes and services in this article, the heart of any server.
Getting started
First and foremost, if you're new to Next.js, the pages/api folder is conventionally where you will add your API methods. The default routing in Next.js is configured out of the box to read this folder and to expose the files located here as public endpoints.
The name of each file is (conventionally) used as the name of the route. If for example you have a user related endpoint that, say, retrieves the users profile picture, then you might have a file in your pages/api folder that resembles the following:
pages -> api -> users -> get-user-profile-image.js
And the subsequent route that you would use to call this endpoint would be:
"api/users/get-user-profile-image"
Because Next.js follows this naming convention from the start, you don't have to wander too much in order to setup a decent structure. So now let's take a look at what that might look like expanded out a few routes.
Folder structure
src/
+-- api/
¦ +-- auth/
¦ ¦ +-- login.js
¦ ¦ +-- register.js
¦ ¦ +-- [...nextauth].js
¦ +-- posts/
¦ ¦ +-- index.js
¦ ¦ +-- [id].js
¦ ¦ +-- create.js
¦ ¦ +-- delete.js
¦ +-- users/
¦ ¦ +-- index.js
¦ ¦ +-- [id].js
¦ ¦ +-- update.js
Let's break down what's happening here. For one, as mentioned above, everything route related goes down in the api/ folder. I personally like to segment my endpoints by category, such as "posts" and "users" and whatever else is related to my project.
And it's not just personal preference here. Next.js file names are used as the URL route, as mentioned above, and to keep in line with convention it makes sense that you are going to have/need multiple index.js and [id].js files per category.
If you're unfamiliar, index.js is a default filename that does not need to be specified in the route URL. For example, pages/api/users/index.js can be called with the following URL:
URL: api/users
Next.js knows to look for the index.js file without needing to specify it. And that means, you guessed it, that you can only use it once per folder. Hence the benefit of segmenting everything out.
But do you have to separate everything, or can you simply just dump every file into the main /api directory? Technically, you can do whatever you want with your server and break free of convention, which is a huge benefit that you often get with Node based projects. The following structure for example, would still be considered valid:
src/
+-- api/
¦ +-- get-posts.js
¦ +-- create-post.js
¦ +-- update-posts.js
¦ +-- delete-post.js
¦ +-- get-user.js
¦ +-- create-user.js
...
URL's: /api/get-posts
/api/create-post
/api/update-post
etc
And that's a commonly seen pattern (that I commonly see) that probably shouldn't be. In a real-world production application you're going to end up with several hundred to several thousand routes and trying to navigate your way through a slew of poorly named files isn't going to help anyone, particularly not your future self.
And to circle back to what I said earlier, this is why it's crucial to setup a proper file and naming system when working on new projects from the very beginning. It's very simple to refactor 5 files into proper categories in the beginning, but it's near impossible to do the same for thousands. At least not without causing substantial issues to other parts of your code.
Non-route folders and files
With routing files out of the way, it is equally as important to organize every other kind of file that you're going to end up needing. That includes random utilities and security-based files.
your-app/
+-- pages/
¦ +-- api/
+-- middleware/
+-- services/
¦ +-- articles.js
¦ +-- users.js
+-- styles/
+-- utils/
Note again, that a real-world production application would probably have substantially more folders and they might not necessarily resemble anything like what's above. This is a great starting point, if you have a simple project that you're working on however.
I typically recommend putting any tertiary non-route folders into the main parent route. This ensures that you know where everything is from the very beginning and you aren't struggling to remember which folder is the parent of so and so.
Utils
Utility, utils, etc. Essentially, these are scripts that perform some kind of system-wide function that you will use frequently. In fact, if you use it more than once, you should put it in your utilities folder. This include, but is not limited, to the following:
- Sanitation functions
- Validation functions
- String manipulation
- Math calculations
- Database operations
If you have a function that removes HTML from a given string for example, this would be the place to add it.
function stripHTML(text) {
// Create a new div element
let div = document.createElement("div");
// Set the textContent or innerHTML of the div to the provided text
div.innerHTML = text;
// Retrieve and return the plain text
return div.textContent || div.innerText || "";
}
I typically just have 1 or 2 files in my utilities folder, mainly utils.js and usually some kind of specialized file that differentiates from regular utilities, just in case that is a use case.
And ideally, you should find yourself constantly adding new features and functions to this library and your projects grow in size.
You of course, don't have to settle for just 2 files. If you're working with multiple 3rd party libraries, and they each require specialized utility functions, then it would make sense to create a separate file for each.
Service functions
Routes are one thing, but your actual coding logic has to live somewhere in an organized manner. You'll commonly find a services folder somewhere in any kind of Node application these days.
your-app/
+-- services/
¦ +-- articles.js
¦ +-- users.js
Similarly to how your API routes are setup, creating a service file for each of those equivalent categories makes sense. This way you won't be fumbling around trying to locate which service 'files' your user routes require. You'll know by naming convention, that it is probably user.js.
I've also seen other developers use user.service.js as the naming convention for service files. This can help to differentiate and locate files much easier as well, when working with a larger number of files.
I also tend to create service files for any 3rd party implementation that I may be using. For example, if I'm using the Slack API for whatever reason I will have a slack.js file as a service file as well.
It's best to keep your services folder away from your /api folder, so that you're not exposing any service files or functions through the public routing system.
Middleware
And similarly to services, having middleware (of any kind) segmented into its own region is just going to help you with scalability in the future. You might not have any type of middleware in the beginning of your project, but it's a good practice to at least have the folder created and ready for whenever you decide to add files into.
And if multiple people are working on a particular application, it also lets them know where to include new files.
your-app/
+-- middleware/
¦ +-- auth.js
¦ +-- apply.js
Just as an example, if you have authentication functionality setup as middleware, creating a separate auth.js file to handle that logic will simplify things going forward. In general, categorizing things in terms of how you would talk about them (in true OOP) fashion can be beneficial for projects that will undoubtedly grow in size and scale.
There isn't any perfect folder structure or system out there today, because every developer and every company will have their own specific needs and requirements. I personally have spent hours setting up new server projects on what I thought was the most ideal file naming convention, only to have that house of cards topple on me within a week.
And for that, you definitely need to know as much about the requirements as possible from the very beginning.
But at the bare minimum, separating out your concerns from the very start will at least reduce the chances of any major overhauls in the future. Hopefully.