Node.js framework NestJS project structure
Started from this issue: nestjs/nest#2249
This example is based on the modules recommended by the NestJS official documentation as default (introduced at the top of the section).
If you focus on the performance or features of the module, you can consider:
- Fastify instead of
Express
- MikroORM instead of
TypeORM
- or DrizzleORM
- or Sequelize
- or Prisma
- SWC instead of
TypeScript compiler
- Vitest instead of
Jest
- ESM instead of
CommonJS
Check out the nestjs-project-performance repository for examples using this alternative.
- Create a
.env
file- Rename the .env.sample file to
.env
to fix it.
- Rename the .env.sample file to
- Edit env config
- Edit the file in the config/envs folder.
default
,development
,production
,test
# 1. node_modules
npm ci
# 2. When synchronize database from existing entities
npm run entity:sync
# 2-1. When import entities from an existing database
npm run entity:load
If you use multiple databases in entity:load
, modify them.
npm run start:dev
# https://docs.nestjs.com/recipes/repl
npm run start:repl
npm test # exclude e2e
npm run test:e2e
npm run lint
npm run build
# define environment variable yourself.
# NODE_ENV=production PORT=8000 NO_COLOR=true node dist/app
node dist/app
# OR
npm start
+-- bin // Custom tasks
+-- dist // Source build
+-- public // Static Files
+-- src
| +-- config // Environment Configuration
| +-- entity // TypeORM Entities
| +-- auth // Authentication
| +-- common // Global Nest Module
| | +-- constants // Constant value and Enum
| | +-- controllers // Nest Controllers
| | +-- decorators // Nest Decorators
| | +-- dto // DTO (Data Transfer Object) Schema, Validation
| | +-- filters // Nest Filters
| | +-- guards // Nest Guards
| | +-- interceptors // Nest Interceptors
| | +-- interfaces // TypeScript Interfaces
| | +-- middleware // Nest Middleware
| | +-- pipes // Nest Pipes
| | +-- providers // Nest Providers
| | +-- * // models, repositories, services...
| +-- shared // Shared Nest Modules
| +-- gql // GraphQL Structure
| +-- * // Other Nest Modules, non-global, same as common structure above
+-- test // Jest testing
+-- typings // Modules and global type definitions
// Module structure
// Add folders according to module scale. If it's small, you don't need to add folders.
+-- src/greeter
| +-- * // folders
| +-- greeter.constant.ts
| +-- greeter.controller.ts
| +-- greeter.service.ts
| +-- greeter.module.ts
| +-- greeter.*.ts
| +-- index.ts
This is the most basic structure to start a NestJS project.
You should choose the right architecture[1] (Layered, Clean, Onion, Hexagonal ...)[2] based on the size of your project.
- See bootstrap, app.module
- Database, Module Router, Static Files, Validation, Pino Logger
- Global Exception Filter
- Global Logging Context Middleware
- Custom Logger with nestjs-pino
- Custom Decorators Example at Nest level
- Configuration
- Authentication - JWT and Session login with Passport
- Role-based Guard
- Controller Routes
- Auth Login
- Sample Parameter and DTO
- CRUD API Sample
- Database Query Example
- Unit Test
- E2E Test
- Shared Modules Example
- GraphQL Structure Example
# APP, Compodoc
npm run doc #> http://localhost:8080
# API, Swagger - src/swagger.ts
npm run doc:api #> http://localhost:8000/api
export class PascalCaseSuffix {} //= pascal-case.suffix.ts
// Except for suffix, PascalCase to hyphen-case
class FooBarNaming {} //= foo-bar.naming.ts
class FooController {} //= foo.controller.ts
class BarQueryDto {} //= bar-query.dto.ts
// https://stackoverflow.com/questions/541912
// https://stackoverflow.com/questions/2814805
interface User {}
interface CustomeUser extends User {}
interface ThirdCustomeUser extends CustomeUser {}
# It is recommended to place index.ts in each folder and export.
# Unless it's a special case, it is import from a folder instead of directly from a file.
- import { FooController } from './controllers/foo.controller';
- import { BarController } from './controllers/bar.controller';
+ import { FooController, BarController } from './controllers';
# My preferred method is to place only one fileOrFolder name at the end of the path.
- import { UtilService } from '../common/providers/util.service';
+ import { UtilService } from '../common';
https://docs.nestjs.com/fundamentals/circular-dependency
# Do not use a path that ends with a dot.
- import { FooService } from '.';
- import { BarService } from '..';
+ import { FooService } from './foo.service';
+ import { BarService } from '../providers';
refer to Naming cheatsheet