89

We have resorted to this following project structure

|- pages
    |- <page_name>
        |- index.js             # To do a default export of the main component
        |- MainComponent.jsx    # Contains other subcomponents
        |- main-component.css   # CSS for the main component
        |- OtherComponents.jsx  # more than 1 file for child components that are used only in that page
        |- __tests__            # Jest unit and snapshot tests
|- components
    |- index.js                 # Exports all the default components of each component as named exports
    |- CommonCmpnt1
        |- CommonCmpnt1.jsx
        |- common-cmpnt-1.css
        |- index.js             # To default export the component
        |- __tests__
    |- CommonCmpnt2
        |- CommonCmpnt2.jsx
        |- common-cmpnt-2.css
        |- index.js             # To default export the component
        |- __tests__

To clarify, nothing has broken and it works amazingly well. We have components that are reused in multiple pages inside the components directory, where we import as follows

// Assuming we are inside MainComponent.jsx
// ...
import { CommonCmpnt1 } from '../../components';    // We even take it a step further and use absolute imports

Also, components that are used only once reside side-by-side in it's pages folder.

The only problem we face now is the Hot Module reloading is broken, i.e. whenever we edit the .jsx file inside either the pages or the components directory, we have to manually reload the page to see effected changes (It doesn't affect the CSS files). It is something that we've grown accustomed to and so doesn't affect us seriously.

My question is, is there any impending catastrophe that we do not know of?

cross19xx
  • 3,170
  • 1
  • 25
  • 40
  • 4
    Well definitely css is not general in next project. they use JS based css. something like `styled components` – Code Maniac Dec 19 '18 at 16:17
  • @CodeManiac I agree, but it's more of a preference that a solution. We alternate between `styled-jsx` (styled components), `sass` and `css` – cross19xx Dec 19 '18 at 16:27

11 Answers11

141

Stumbled upon this post while searching for a suitable folder structure for NextJS myself. I've been using a similar structure but recently found that this is not how you're suppose to use NextJS.

I don't know too much about the details, but NextJS has optimizations at the page level. When you build a NextJS project, you will see the pages logged as part of the build. NextJS treats every component file under the pages folder as a page, so by placing non-page components in the pages folder, you are drastically increasing build time because now NextJS goes and builds every one of those components as a page.

Hans
  • 2,610
  • 3
  • 17
  • 20
  • 1
    I agree... and believe me, I found out the hard way. I'm yet to make an edit on this post but yours will be appreciated – cross19xx Jan 27 '20 at 07:19
  • 2
    Yeah... I found out the hard way as well, was wondering why a build took minutes :o – Hans Jan 27 '20 at 18:19
  • 2
    I agree with this. I also learnt the hard way. Now I consider pages as routing and put only stuff that needs to be rendered on the server and import everything dynamically from components folder. Makes it easy to switch to non nextjs projects as well – apnerve Feb 24 '20 at 07:17
  • So what is the correct solution? Your answer suggests that components are not supposed to go under `pages` , so where are they supposed to go? – Rylan Schaeffer Jun 10 '22 at 00:17
  • 1
    @RylanSchaeffer you can add them in the common folder. Pages folder is only supposed to host pages not component. If you put a component in pages like pages/ home/ myComponent.tsx it wil generate a page like localhost:3000/home/myComponent – Shazil Sattar Jun 20 '22 at 08:33
49

UPDATE 2023: Since Next.js introduced the new app directory and the new file colocation improvement,you can adjust my previous proposition to the project organization structure that best suits your needs. Project Organization and File Colocation on NextJS Documentation

I like the structure proposed in this article

https://medium.com/@pablo.delvalle.cr/an-opinionated-basic-next-js-files-and-directories-structure-88fefa2aa759

/root
  \_ /.next/
  \_ /components/
      \_ Button/
          \_ button.spec.jsx
          \_ button.styles.jsx
          \_ index.jsx
  \_ /constants/
      \_ theme.js
      \_ page.js
  \_ /contexts/
      \_ Locale/
         \_ index.js
      \_ Page/
         \_ index.js
  \_ /pages/
      \_ _app.jsx
      \_ _document.jsx
      \_ about.jsx
      \_ index.jsx
  \_ /providers/
      \_ Locale/
         \_ index.js
      \_ Page/
         \_ index.js
  \_ /public/
      \_ favicon.ico
      \_ header.png
  \_ /redux/
      \_ actions/
         \_ users/
            \_ index.js
         \_ products/
            \_ index.js
      \_ reducers/
         \_ users/
            \_ index.js
         \_ products/
            \_ index.js
      \_ store/
         \_ index.js
      \_ types/
         \_ index.js
  \_ /shared/
      \_ jsons/
          \_ users.json
      \_ libs/
          \_ locale.js
      \_ styles/
          \_ global.css
  \_ /widgets/
      \_ PageHeader/
          \_ index.jsx
  \
  \_ .eslintignore
  \_ .eslintrc
  \_ .env
  \_ babel.config.js
  \_ Dockerfile
  \_ jest.config.js
  \_ next.config.js
  \_ package.json
  \_ README.md
Daher
  • 1,001
  • 10
  • 10
16

If someone is still interested, I save the file depending on its type in my project, for example:

|-Nextjs-root
  |-Components
    |-Header.js
    |-Footer.js
    |-MoreExamples.js
  |-styles
   |-globals.css
   |-header.module.css
   |-footer.module.css
  |-Services
    |-api              #Axios config to connect to my api
  |-Context
   |-AuthContext.js    #Global context to my app for auth purposes
  |-pages
   |-index.js
TechWisdom
  • 3,960
  • 4
  • 33
  • 40
Gabriel Taype
  • 192
  • 3
  • 6
  • I doubt server side debugger won't work for `Services/api` because I guess next.js creates source map only for files inside pages directory – Nika Tsogiaidze Feb 07 '22 at 11:17
  • 2
    This doesn't scale. [Folder-by-feature](https://softwareengineering.stackexchange.com/a/338610/373878) is better for mid-big projects. – Spankied Sep 25 '22 at 01:50
8

Here is what I recommend, using a modular design pattern:

/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

I wrote an article about it: https://dev.to/vadorequest/a-2021-guide-about-structuring-your-next-js-project-in-a-flexible-and-efficient-way-472

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

Vadorequest
  • 16,593
  • 24
  • 118
  • 215
  • 1
    What about styling? module css files and global css files ? – Naor Oct 06 '21 at 21:00
  • 2
    For component-level CSS files, they can either be included inside the `.tsx` file (when using CSS-in-JS), or with a `.css` file alongside. (in the same folder, with the component's name) – Vadorequest Oct 07 '21 at 11:33
  • For global styles, I have a special `src/app` folder that contains everything that affects the app in its whole. As I use CSS-in-JS, I have a `src/app/components/GlobalStyles.tsx` file that contains all global styles (within a `Global` component from the `@emotion/react` library). – Vadorequest Oct 07 '21 at 11:36
  • 1
    Where do you keep your Page components? I mean: `pages/about.tsx` will most likely render an `About.tsx` component. Ofc, `about` is usually a very simple component, but we could also be speaking about `pages/posts/[id].tsx` that will render a `PostContainer` that handles dynamic data, etc. Where do you keep those, since they cannot be inside the `pages` routing folder? Also, if you can, have a look at: https://github.com/vercel/next.js/discussions/34130 – cbdeveloper Feb 09 '22 at 15:30
  • @cbdeveloper Usually in a `/modules` subfolder. – Vadorequest Feb 10 '22 at 12:12
6

To all who are still interested in this, I personally recommend this approach due to the fact that it helps compartmentalize resources and allows for quickly finding things and unit testing.

It was inspired by an article by HackerNoon on How to structure your React app

cross19xx
  • 3,170
  • 1
  • 25
  • 40
  • 7
    Half a year later are you still using this structure? Anything you've learned along the way? Thanks for this – Scott L Jul 14 '19 at 04:50
  • Sorry for the delay in response. Yes, I got to learn a lot. For starters, Next treats everything inside the pages as a directory, so it basically treats all the files as individual pages. This may not necessarily be a security breach in all cases, but better safe than sorry. – cross19xx Jan 27 '20 at 10:49
  • 1
    This is what I'm worried about, your MainComponent.jsx file and OtherComponents.jsx file is in a folder under pages, then wouldn't it display the page, if you typed it in your url? – hellomello Feb 11 '20 at 04:32
  • it will. Take for example the page name is about. If you visit /about, /about/index, they will both work. The only downside to this is that if you type /about/OtherComponent, it will work and try to render the other component – cross19xx Feb 11 '20 at 08:36
  • I'd rather use something like this: https://dev.to/vadorequest/a-2021-guide-about-structuring-your-next-js-project-in-a-flexible-and-efficient-way-472 – Vadorequest Feb 24 '21 at 08:51
  • Not entirely sure why adding the name 'bundles' is particularly useful. Will you have multiple bundles? I doubt it. Everything is in src, and that is pretty much a standard across most npm packages. Having a common/ folder maybe ok for separation of non common items, but otherwise a 'components' folder is pretty much self explanatory. – Steve Tomlin May 09 '21 at 14:00
5

There no a correct way to define your struture. This is how i defined

  • src
    • components
      • layout.js --- component inside components folder, more than one page will use this component
      • templates --- components to a specific page
        • home -- homePage
          • article.js -- Article Component
      • ui --- styled components, ex: Button, Title, Link
    • pages
    • styles
  • public
Max
  • 393
  • 4
  • 4
5

I use the pages directory only for routing purposes.

this way you can keep a clean directory structure and keep components near their parent components.

src
├── shared-components
│   └── ...
├── pages-components
│   ├── page-1
│   │   ├── index.tsx
│   │   ├── FooComponent.tsx  // page-1 specefic component
│   │   └── ...
│   └── home-page
│       └── index.tsx
└── pages                     // just for routing
    ├── page-1               
    │   └── index.ts          // export default from 'src/page-components/page-1'
    └── index.ts              // export default from 'src/page-components/home-page'
Saman Mohamadi
  • 4,454
  • 4
  • 38
  • 58
3

Make sure to separate backend-only files from frontend + backend files

Regardless of what you name them, I would recommend having two directories with very clear semantics:

  • the backend-only directory: can make backend-only operations, e.g. direct DB or filesystem accesses (require('fs'))
  • the frontend + backend directory: frontend safe things only. Since Next.js is an SSR setup, anything that is frontend safe also has to be backend safe, so you can also use them from the backend, e.g. shared configs or helpers.

This is important because otherwise you will start to hit errors such as:

Module not found: Can't resolve 'fs'

when factoring things out with HoCs, and as mentioned at Module not found: Can't resolve 'fs' in Next.js application I do not know how to solve this except by making this clear and definite split.

Perhaps this is the intended semantic of the lib/ vs components/ convention commonly used, but I couldn't find a clear quote.

I'm more tempted to just call them back/ and front/

ESLint pages/, components/, and lib/ by default

This is the only clear in-upstream-code effect of components/ and lib/ that I could find as mentioned at: https://nextjs.org/docs/basic-features/eslint#linting-custom-directories-and-files (pages/ of course is magic and contains the URL entry points, and you should obviously not put anything else there):

By default, Next.js will run ESLint for all files in the pages/, components/, and lib/ directories.

It doesn't matter much in that case as the directory list can be easily configured as documented there.

Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
2

The way that now suit me most is to use the pages folder only for routing purpose, components in each file is just a wrapper for the "real" page components in src folder. With this approach I can structure my homepage more easily and it feel more intuitive - to contain the layout and its child components at the same folder.

Phạm Huy Phát
  • 783
  • 9
  • 17
0

All these answers are very good, even the one that got downvoted but could use clarification. Its a tough decision to make when your about to start a new app that you know will grow to become quite large; the patterns you define now, you will be stuck with for years, and that's the goal, good patterns that work for a long time. Another goal is translatability if the pattern needs to change it shouldn't seem like an impossible task.

To expand on @Anamol Maharjan's Answer. One can actually do traditional TS best practices folder structure using this technique: https://nextjs.org/docs/api-reference/next.config.js/custom-page-extensions

By defining the extensions for pages (maybe even api but haven't tried). Routing is natural while TS best practices are maintained... primarily the idea to group by subject, not type, grouping by type only without subject in the hierarchy become problematic. Thus one should strive for a subject/type restricted structure along with a common folder with type defined subfolders.

In that regard, one can use this package to do:

pages/
  api/
  common/
   data/
   views/
     controls/
       Button.jsx
     indicators/
       Badge.jsx
   styles/
  page/
    login/
      data/
        LoginHandler.tsx
        LoginRequest.tsx
      views/
        modals/
          PasswordReset.tsx
      Login.page.tsx

In terms of preference, ATM our app is using pages dir solely for routes... but then we end up with common/pages and we really want to change the nextjs pages dir to be named routes. So we are debating this solution. It's a complex analysis to pick the best for a given application unfortunately. Once you start adding verbose testing with all its possible approaches, storybook, all these other things nextJS seems not to wrap, configure and recommend, it gets complicated.

Safest Options Appear to be (in no particular order):

  • Module approach > no page specific modules, just global modules
  • .pages.ts extension restriction > seems to make it a pure TS app again with added features. It replicates the new nextJS app folder as well, which isn't anywhere near ready IMHO at time of writing. If we had a config option to change pages to app and to move api, I think there is little need for the app dir... that could be all the app dir is and the rest of it is server side stuff, backend features added to support that abstraction; it may translate well. This, hopefully, also compensates for the over compiling problem described in the accepted answer.
  • page container component only in pages dir > page specific tests cannot live there and if you have page specific components, you end up with another pages dir in common.
gunslingor
  • 1,358
  • 12
  • 34
-3

There is likely no definite way to structure your folders, it will again all depend on what makes things easier for you.

This is how I usually structure my application

pages/
├─ assets/
│   ├─ images/
│   ├─ icons/
│   └─ misc/
├─ components/
│   ├─ Buttons/
│   ├─ Cards/
│   └─ ...
├─ config/
│   └─ config.ts         //configuration constants such as ip,keys etc
├─ constants/
├─ contexts/             // all your context files
├─ helpers/              // any extra functions
├─ hooks/                // for intricate react hooks
├─ interfaces/           // for typescript interfaces
├─ layouts/              // for all layout files
├─ modules/              // if you develop each module seperately
├─ pages/          
├─ services/             // for all your api calls
├─ styles/