项目结构解析
本教程共 47 篇 · 第 4 篇 · 更新于 2026-08-09 · 约 9 分钟阅读
本节目标:搞清楚 NestJS 项目里每个文件、每个目录是干嘛的,学会按规范组织自己的代码。
默认项目结构
用 nest new 创建项目后,你会看到这样一堆文件:
my-project/
├── node_modules/
├── src/
│ ├── app.controller.spec.ts
│ ├── app.controller.ts
│ ├── app.module.ts
│ ├── app.service.ts
│ └── main.ts
├── test/
│ ├── app.e2e-spec.ts
│ └── jest-e2e.json
├── .eslintrc.js
├── .gitignore
├── .prettierrc
├── nest-cli.json
├── package.json
├── tsconfig.build.json
└── tsconfig.json
文件不少,但核心就 src/ 下的那几个。其余的要么是配置文件,要么是测试文件。
src 目录:代码都在这
src/ 是源代码目录,你写的所有业务代码都放这里。
src/
├── main.ts # 应用入口
├── app.module.ts # 根模块
├── app.controller.ts # 根控制器
├── app.controller.spec.ts # 控制器的单元测试
└── app.service.ts # 根服务
每个文件的职责:
main.ts — 应用的启动入口。创建 NestJS 应用实例,配置全局设置,启动 HTTP 服务器。上一章已经看过了。
app.module.ts — 根模块,整个应用的”总装配图”。所有功能模块都挂在它下面。
app.controller.ts — 根控制器,处理根路径 / 的请求。脚手架默认给了一个返回 “Hello World!” 的路由。
app.service.ts — 根服务,包含业务逻辑。脚手架默认给了一个 getHello() 方法。
app.controller.spec.ts — 控制器的单元测试文件。NestJS 很重视测试,所以连脚手架都帮你把测试文件生成好了。
Tip如果你不需要测试文件,生成时加
--no-spec参数就行:nest g service users --no-spec。
配置文件逐个看
nest-cli.json
Nest CLI 的配置文件:
{
"$schema": "https://json.schemastore.org/nest-cli",
"collection": "@nestjs/schematics",
"sourceRoot": "src",
"compilerOptions": {
"deleteOutDir": true
}
}
几个关键配置:
| 配置项 | 说明 |
|---|---|
sourceRoot | 源代码目录,默认 src |
collection | CLI 生成代码时用的模板集 |
compilerOptions.deleteOutDir | 构建前是否清空输出目录 |
Note
deleteOutDir: true这个配置很实用。每次nest build时会先清空dist/目录,避免残留旧文件。
tsconfig.json
TypeScript 的配置文件。NestJS 脚手架帮你配好了关键选项:
{
"compilerOptions": {
"module": "commonjs",
"declaration": true,
"removeComments": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"allowSyntheticDefaultImports": true,
"target": "ES2021",
"sourceMap": true,
"outDir": "./dist",
"baseUrl": "./",
"incremental": true,
"skipLibCheck": true,
"strictNullChecks": true,
"noImplicitAny": true,
"strictBindCallApply": true,
"forceConsistentCasingInFileNames": true,
"noFallthroughCasesInSwitch": true
}
}
有两个配置是 NestJS 必须的,千万别删:
emitDecoratorMetadata: true— 发射装饰器的元数据,NestJS 的依赖注入靠它工作experimentalDecorators: true— 启用装饰器语法
Tip很多人遇到”依赖注入不生效”的问题,最后发现是这两个选项没开。记住,NestJS 项目里这俩是必须的。
tsconfig.build.json
这个是构建专用的 TS 配置,继承自 tsconfig.json,额外排除了测试文件:
{
"extends": "./tsconfig.json",
"exclude": ["node_modules", "test", "dist", "**/*spec.ts"]
}
平时不用改它。
.prettierrc
代码格式化配置。NestJS 默认用 Prettier 来统一代码风格。
.eslintrc.js
代码规范检查配置。默认用 ESLint 来检查代码质量问题。
test 目录:端到端测试
test/
├── app.e2e-spec.ts # E2E 测试文件
└── jest-e2e.json # Jest E2E 配置
E2E 测试(End-to-End)是模拟真实用户请求来测试整个应用。和单元测试不同,单元测试测的是单个类或方法,E2E 测的是完整的请求链路。
跑 E2E 测试:
npm run test:e2e
命名规范
NestJS 有一套严格的文件命名规范。遵循这套规范,别人一看文件名就知道文件里是什么。
文件命名
| 类型 | 文件名格式 | 示例 |
|---|---|---|
| 模块 | *.module.ts | users.module.ts |
| 控制器 | *.controller.ts | users.controller.ts |
| 服务 | *.service.ts | users.service.ts |
| DTO | *.dto.ts | create-user.dto.ts |
| 实体 | *.entity.ts | user.entity.ts |
| 接口 | *.interface.ts | user.interface.ts |
| 守卫 | *.guard.ts | jwt-auth.guard.ts |
| 中间件 | *.middleware.ts | logger.middleware.ts |
| 管道 | *.pipe.ts | validation.pipe.ts |
| 拦截器 | *.interceptor.ts | logging.interceptor.ts |
| 过滤器 | *.filter.ts | http-exception.filter.ts |
类命名
类名用 PascalCase,加上对应的后缀:
| 类型 | 类名格式 | 示例 |
|---|---|---|
| 模块 | XxxModule | UsersModule |
| 控制器 | XxxController | UsersController |
| 服务 | XxxService | UsersService |
| DTO | XxxDto | CreateUserDto |
| 守卫 | XxxGuard | JwtAuthGuard |
Note这些不是强制要求,但强烈建议遵守。团队协作时,统一的命名规范能省掉很多沟通成本。
推荐的目录组织
小项目用默认的 src/ 平铺就够了。项目一大,你需要更好的组织方式。
推荐按”功能模块”来组织目录:
src/
├── main.ts
├── app.module.ts
│
├── common/ # 公共模块
│ ├── decorators/ # 自定义装饰器
│ ├── filters/ # 全局异常过滤器
│ ├── guards/ # 全局守卫
│ ├── interceptors/ # 全局拦截器
│ ├── middleware/ # 全局中间件
│ └── pipes/ # 全局管道
│
├── config/ # 配置相关
│ ├── database.config.ts
│ └── configuration.ts
│
├── modules/ # 功能模块
│ ├── auth/ # 认证模块
│ │ ├── auth.module.ts
│ │ ├── auth.controller.ts
│ │ ├── auth.service.ts
│ │ ├── dto/
│ │ │ ├── login.dto.ts
│ │ │ └── register.dto.ts
│ │ └── strategies/
│ │ └── jwt.strategy.ts
│ │
│ ├── users/ # 用户模块
│ │ ├── users.module.ts
│ │ ├── users.controller.ts
│ │ ├── users.service.ts
│ │ ├── dto/
│ │ │ ├── create-user.dto.ts
│ │ │ └── update-user.dto.ts
│ │ └── entities/
│ │ └── user.entity.ts
│ │
│ └── products/ # 产品模块
│ ├── products.module.ts
│ ├── products.controller.ts
│ └── products.service.ts
│
└── database/ # 数据库相关
├── migrations/
└── seeds/
核心思路:
- common/ 放全局共享的东西(过滤器、守卫、管道等)
- config/ 放配置文件
- modules/ 按业务功能划分模块,每个模块一个目录
- database/ 放数据库迁移和种子数据
Tip不用一开始就搞这么复杂。项目刚开始时简单组织就行,等功能多起来了再逐步重构。别过度设计。
单个模块的目录结构
一个功能模块内部,推荐这样组织:
users/
├── users.module.ts # 模块定义(必须有)
├── users.controller.ts # 控制器
├── users.service.ts # 服务
├── dto/ # 数据传输对象
│ ├── create-user.dto.ts
│ └── update-user.dto.ts
├── entities/ # 数据实体
│ └── user.entity.ts
└── interfaces/ # TypeScript 接口
└── user.interface.ts
不是每个模块都需要这些子目录。简单的模块可能只有一个 module、一个 controller、一个 service,三个文件就够了。
用 CLI 快速生成代码
Nest CLI 能帮你生成各种文件,不用手动创建:
# 生成模块
nest g module users
# 生成控制器
nest g controller users
# 生成服务
nest g service users
# 生成守卫
nest g guard auth/jwt
# 生成拦截器
nest g interceptor logging
# 生成过滤器
nest g filter http-exception
# 生成管道
nest g pipe validation
# 生成装饰器
nest g decorator current-user
# 生成中间件
nest g middleware logger
常用选项:
# 不生成测试文件
nest g service users --no-spec
# 注册到指定模块
nest g controller users --module app
Note用 CLI 生成模块时,Nest 会自动把它注册到根模块的
imports里。手动创建模块的话,别忘了自己注册。
代码分层
NestJS 推荐一个清晰的分层架构:
请求 → Controller → Service → Repository → 数据库
↓ ↓
DTO Entity
- Controller:接收请求,提取参数,调用 Service,返回响应
- Service:处理业务逻辑,调用 Repository
- Repository:操作数据库(用 TypeORM、Prisma 等)
- DTO:定义请求参数的结构
- Entity:定义数据库表的结构
每一层只干自己的事,不越界。Controller 不直接操作数据库,Service 不直接处理 HTTP 请求。
小结
NestJS 的项目结构看着文件多,但规律很清晰:
src/下写代码,按功能模块组织- 文件命名有规范,看名字就知道类型
- CLI 帮你生成大部分样板代码
- 分层架构让代码职责清晰
掌握了项目结构,后面学模块、控制器、服务这些概念时,你就知道它们分别放在哪里了。