VienDinhCom/next-full-stack

How to Organize a Next.js Full Stack Project

Opened this issue ยท 5 comments

Hi there! In this article, I want to show you how I organize my Next.js Full Stack Project.

Folder Structure

First of all, you can take a look at the folder structure below. You can see that src is the root-level application project. Yes! I want to place my code into the src folder.

  • src
    • backend
      • entities
      • migrations
      • resolvers
      • services
    • frontend
      • components
      • services
    • pages
      • api
      • app
    • shared
      • schemas
      • services

Shared Folder

I often have some code that I want to use for both frontend and backend, such as schemas for typed-safe API, services for accessing environment variables or utility functions, ...

With these kinds of code, I want to place them into the shared folder.

Backend Folder

In the backend folder, I want to place my server code, such as:

  • entities is for TypeORM entities.
  • migrations is for TypeORM migrations.
  • resolvers is for resolvers of API schemas.
  • services is to place reusable code for resolvers.

Frontend Folder

In the frontend folder, I want to place my client code, such as:

  • components is for reusable components
  • services is to place reusable code for components and pages.

Pages Folder

pages is the default Next's folder for routing. Inside the pages folder, I have:

  • api is for server API handlers.
  • app is for the main authenticated app.

Setup Next.js

In this section, I will set up a Next.js application with the folder structure above.

Generate Next.js application

First, I will create a new Next.js application named next-full-stack with the command below.

yarn create next-app next-full-stack

Next, I change the working folder to next-full-stack.

cd next-full-stack

Next, I remove these Next.js default folders.

rm -rf styles pages

Next, I create a new folder named src to store all my code.

mkdir src

Finally, I change the working folder to src to ready for the next steps.

cd src

Create Folders

To organize the folder structure which we have, I will run these command to create the folders.

Create Main Folders

mkdir shared backend frontend pages

Create Shared's Sub Folders

mkdir shared/services shared/schemas

Create Backend's Sub Folders

mkdir backend/entities backend/migrations backend/resolvers backend/services

Create Frontend's Sub Folders

mkdir frontend/components frontend/services

Create Home Page

To create the home page for my project, I'll create a text file named index.tsx in the pages folder. The file will have the content below.

touch pages/index.tsx
export default function Page() {
  return <h1>Hello World!</h1>;
}

Add TypeScript Support

I'd like to work with TypeScript on this project. So I will do these steps to have TypeScript support.

yarn add --dev typescript @types/react @types/node

Run this command to let Next.js create next-env.d.ts and tsconfig.json files for TypeScript configuration.

yarn dev

Configure module aliases

Using relative import like this import mod from '../../../mod.ts' is so ugly. So I will add these lines to tsconfig.json, section compilerOptions to make my import code more beautiful.

"baseUrl": "src",
"paths": {
  "@backend/*": ["backend/*"],
  "@frontend/*": ["frontend/*"],
  "@shared/*": ["shared/*"]
}

And my new tsconfig.json will look like this.

{
  "compilerOptions": {
    "target": "es5",
    "lib": ["dom", "dom.iterable", "esnext"],
    "allowJs": true,
    "skipLibCheck": true,
    "strict": false,
    "forceConsistentCasingInFileNames": true,
    "noEmit": true,
    "esModuleInterop": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "jsx": "preserve",

    "baseUrl": "src",
    "paths": {
      "@backend/*": ["backend/*"],
      "@frontend/*": ["frontend/*"],
      "@shared/*": ["shared/*"]
    }
  },
  "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
  "exclude": ["node_modules"]
}

From now on, I can import my child modules with these lines:

import { EnvService } from '@shared/services/env.service.ts'

Or

import { UserService } from '@backend/services/user.service.ts'

Or

import { ApiService } from '@frontend/services/api.service.ts'

Demo: https://next-full-stack-git-issue-1.maxvien.vercel.app/

Source Code

You can find the source code of this tutorial in this branch: https://github.com/maxvien/next-full-stack/tree/issue-1

Now you can create next app with typescript enabled by default via:

yarn create next-app next-full-stack --typescript

Hi @Maxvien! This proposal is definitely a great approach to organising projects in Next.js (enforce cohesion, good discoverability and good understandability of the project). Personally, I like to follow your structure but adding an additional level of grouping within the main categories:

  • backend
    • modules
      • auth
      • ...
    • shared (reuse across backend modules)
      • lib
      • utils
      • ...
  • frontend
    • modules (or pages)
      • auth
        • Auth.tsx
        • components
        • hooks
        • ...
    • shared (reuse across frontend modules)
      • components
      • hooks
      • ...
  • pages
    • api
    • auth
    • ...
  • shared (reuse across backend/frontend)
    • utils
    • core
    • ...

Hey @Maxvien, my project was becoming so convoluted and it didn't feel sustainable. Thanks for posting this cause it brought a LOT more clarity to my project. The tsconfig.json was really the key that brought it all together. The only thing I changed was "client/server" instead of "frontend/backend". Thank you!

@Maxvien I like your approach better

Any One can share for new Next JS 14, App Router