A 2021 guide about structuring your Next.js project in a flexible and efficient way
Tags: nextjs, project, react
Published: 2021-01-21 14:15:27

# Next.js

Next.js is very unopinionated about how to structure your Next.js project. 

> The only thing you must really be careful about is to not have anything under `pages` that aren't actual pages (e.g: tests, components, etc.), because there is no way to ignore them and Next will bundle and deploy them as actual pages.

You can choose to have your code at the root level (`/pages`) or under `src` (`/src/pages`). We prefer the latter, because it makes it more obvious what is actual app-related code and what isn't. 

# The usual folder structure

Most people will organize their project using a folder structure such as:
```
/public
    favicon.ico
/src
    /components
        /elements
            /auth
                AuthForm.tsx
                AuthForm.test.ts
            /[Name]
                [Name].tsx
                [Name].test.ts
    /hooks
    /types
    /utils
    /test
        /api
            authAPI.test.js
            [name]API.test.js
        /pages
            index.test.js

    /pages
        /api
          /authAPI
              authAPI.js
          /[name]API
              [name]API.js
        _app.tsx
        _document.tsx
        index.tsx
```

This design pattern is very common, and it's great for small project because it makes it obvious where your files should be located. They're grouped by "kind of files". It's very similar to the MVC design pattern many developers are familiar with.

The main issue with this design pattern is its lack of scalability. 

While it's great at the beginning, _and can be a good fit depending on the size of your project_, you'll realize a some point you'd find your files faster if they were grouped together by "**module**".

Once you reach 6-10 unrelated features, you'll wish to have the components files close to the utilities and to the TS type that are specific to your UI components, or even maybe your data model.

Also, you might prefer having all files related to a particular 3rd party within the same folder, as a module. (e.g: Sentry, Amplitude, etc.)

At some point, splitting files based on their kind will not be good enough. **That's where you'll need modules**.

# The flexible and "modular" folder structure

Another way to organize things is to introduce **modules**.
Modules help group together code that is related to each other. They're not a replacement for what's common.

Here is how we might convert our previous folder structure to something a bit more modular:

```
/public
    favicon.ico
/src
    /common
        /components
            /elements
                /[Name]
                    [Name].tsx
                    [Name].test.ts
        /hooks
        /types
        /utils
    /modules
        /auth
            /api
                AuthAPI.js
                AuthAPI.test.js
            /components
                AuthForm.tsx
                AuthForm.test.ts
            auth.js
    /pages
        /api
          /authAPI
              authAPI.js
          /[Name]API
              [Name]API.js
        _app.tsx
        _document.tsx
        index.tsx
```

We added a new `src/modules/` folder where we group all files related to the same feature (here, the authentication as "auth"), instead of splitting the "auth" code everywhere, it is now centralized into a single folder.

You might have noticed the only thing that hasn't changed is the `src/pages/` directory. I'll repeat myself, but you must not have anything there that isn't either a page or an API endpoint.

Everything related to the authentication is now in `/src/modules/auth`, it's much easier/faster to understand the code being used to authenticate now!

But, you don't want to always use modules, right? Sometimes you're writing some kind of utility that doesn't really fit in any module, something you'll want to write some code quickly and be done with it. 

Modules introduce "thoughts complexity", because now you have a conscious choice to make about where your file should be. It was easier before to make this decision, because grouping files by kind is effortless, it's a choice that has an actual answer to it. Moving a component to the `hooks` folder is wrong, while moving it to the `components` is correct. 

**It's easy to know you did it right.** (or wrong)

But, with modules, there is no right/wrong answer! Making it harder to make decisions. Sometimes you won't know, it won't be obvious at first (it may never be). Sometimes you'll figure it out afterwards ("oh, that's actually a module").

And because modules aren't the universal solution to this problem, **the key is to allow both**.

The `common` directory should be used for everything that isn't a module, while the `modules` directory should be used by everything you feel should be a "module".

This way, you get the best of both worlds:
- The ability to **quickly** add code **without thinking** much about where it should be (`common`).
- The ability to organize **at your own pace** when you feel like that thing has grown too big and all those pieces of code should be brought together (converting from `common` to `modules`).
- The ability to **quickly find your code** in your existing modules and to have an **overview** of how big a module is. 

I'm the author of [Next Right Now](https://github.com/UnlyEd/next-right-now), a Next.js production-ready boilerplate, and the above folder structure is what we're using since January 20, 2021. It is the result of [feedbacks from the NRN community](https://github.com/UnlyEd/next-right-now/discussions/183).

Alongside this new folder structure, Next Right Now has also migrated to "[Module path aliases](https://unlyed.github.io/next-right-now/reference/module-path-aliases)", which uses absolute paths instead of relative paths for importing modules. (e.g: `import ('@/common/hooks/useStuff')` instead of `import ('../../../common/hooks/useStuff')`.

If you want to learn more on the topic, read the [NRN folder structure documentation](https://unlyed.github.io/next-right-now/reference/folder-structure)!