Skip to content
环境与工具
先把工具链准备好。
Nest CLI 是一个全局命令行工具,用来创建项目、生成文件、执行构建和运行开发服务器。安装走 npm:
bash
npm install -g @nestjs/cli如果需要特定版本,指定版本号即可:
bash
npm install -g @nestjs/cli@版本号装完验证:
bash
nest --version输出类似 10.x.x 的版本信息就表示安装成功。
Linux/macOS 下全局安装遇到权限问题时,在命令前加 sudo,或者把 npm 的全局前缀配置到用户目录。如果装错了或要升级,先卸载再重装:
bash
npm uninstall -g @nestjs/cli
npm cache clean --forceNode.js 版本要求:NestJS 10.x 需要 Node.js 16 或更高,具体以当前版本的官方说明为准,不要用太老的 LTS 版本。
创建第一个 NestJS 项目
nest new 是 NestJS 中的第一个命令,也是最常用的命令。
bash
nest new my-first-nest执行过程分两步:
- CLI 提示选择包管理器:npm、yarn 或 pnpm。
- 选定之后,CLI 自动安装依赖并生成项目骨架。
别名是 nest n,效果相同。
命名上需要注意:项目名建议用短横线命名(kebab-case),比如 my-first-nest。Nest CLI 会根据项目名推断模块和类的命名,用大写驼峰会生成不符合预期的目录名。
nest new 默认会初始化一个 Git 仓库,并通过 package.json 锁定依赖版本。如果只是想快速试一下,不需要 Git,可以用 --skip-git 跳过:
bash
nest new quick-test --skip-git生成的目录结构在下一节展开。
项目结构快速导航
刚生成的项目结构如下:
my-first-nest/
├── src/
│ ├── app.controller.ts
│ ├── app.controller.spec.ts
│ ├── app.module.ts
│ ├── app.service.ts
│ └── main.ts
├── test/
│ ├── app.e2e-spec.ts
│ └── jest-e2e.json
├── nest-cli.json
├── package.json
├── tsconfig.json
├── tsconfig.build.json
└── node_modules/这里聚焦 src/ 下的四个核心文件,它们是应用最基本的骨架。
main.ts
typescript
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
await app.listen(3000);
}
bootstrap();bootstrap 函数是整个应用的入口。它用 NestFactory.create() 加载根模块 AppModule,然后监听 3000 端口。这里没有 Express 的 app.listen 调用细节——Nest 包装了一层,底层默认用 Express,可以切到 Fastify。
端口 3000 是硬编码的默认值。部署时通常从环境变量读取。
app.module.ts
typescript
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
@Module({
imports: [],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}AppModule 是应用的根模块。@Module() 装饰器里的 controllers 和 providers 就是之前文章讲过的概念:控制器处理路由,提供者承载业务逻辑。imports 目前是空数组,后续添加其他模块时填在这里。
app.controller.ts
typescript
import { Controller, Get } from '@nestjs/common';
import { AppService } from './app.service';
@Controller()
export class AppController {
constructor(private readonly appService: AppService) {}
@Get()
getHello(): string {
return this.appService.getHello();
}
}@Controller() 不带参数意味着路由前缀是 /。@Get() 绑定到 HTTP GET 方法。constructor 里的 appService 参数是依赖注入的入口——Nest 会从模块的 providers 里找到 AppService 并注入实例。
app.service.ts
typescript
import { Injectable } from '@nestjs/common';
@Injectable()
export class AppService {
getHello(): string {
return 'Hello World!';
}
}@Injectable() 告诉 Nest 这个类可以被注入。目前只有一个 getHello 方法,返回固定字符串 'Hello World!'。这就是访问 http://localhost:3000/ 时看到的内容来源。
用 CLI 生成模块
实际开发不会把所有东西堆在一个 AppModule 里。模块按功能边界划分,比如用户相关的都放到一个 UsersModule 中。
手工创建模块需要三步:新建文件、写 @Module() 装饰器、在根模块的 imports 里手动注册。Nest CLI 的 generate module 把这些一步做完:
bash
nest generate module users执行后,CLI 做了两件事:
- 在
src/users/下生成users.module.ts; - 自动更新
app.module.ts,把UsersModule加到imports数组里。
别名:nest g module users 或 nest g mo users。
生成的 UsersModule 是一个空模块:
typescript
import { Module } from '@nestjs/common';
@Module({})
export class UsersModule {}@Module({}) 是合法的,后续加上 controllers 和 providers 即可。
生成控制器与服务并编写接口
模块有了,接着往里面加控制器和服务。
生成控制器
bash
nest generate controller usersCLI 输出:
- 创建
src/users/users.controller.ts - 创建
src/users/users.controller.spec.ts(单元测试文件) - 更新
src/users/users.module.ts,把UsersController注册到controllers数组
别名:nest g co users。
生成服务
bash
nest generate service users类似地:
- 创建
src/users/users.service.ts和它的测试文件 - 更新
users.module.ts,把UsersService加到providers数组
nest generate resource 可以一次性生成完整的 CRUD 资源,包含模块、控制器、服务和 DTO 文件,比分三次生成更省事。这里先用分开的方式,行为更透明。
控制器注入服务
生成出来的 UsersService 是一个空壳:
typescript
import { Injectable } from '@nestjs/common';
@Injectable()
export class UsersService {}先给它加一个方法:
typescript
@Injectable()
export class UsersService {
findAll(): string[] {
return ['user1', 'user2', 'user3'];
}
}然后到 UsersController 里通过构造函数注入:
typescript
import { Controller, Get } from '@nestjs/common';
import { UsersService } from './users.service';
@Controller('users')
export class UsersController {
constructor(private readonly usersService: UsersService) {}
@Get()
findAll(): string[] {
return this.usersService.findAll();
}
}这里有两点值得注意:
@Controller('users')指定路由前缀是/users,这个控制器里的所有路由都挂在这个前缀下面。constructor(private readonly usersService: UsersService)是注入点。TypeScript 编译后保留了类型元数据,Nest 靠这个元数据知道该注入哪个 Provider。
编写 GET 端点
上面的 @Get() 不带参数,匹配 GET /users。需要路径参数时,用 @Param() 装饰器:
typescript
@Get(':id')
findOne(@Param('id') id: string): string {
return `user ${id}`;
}至此,UsersModule 有了一个控制器和一个服务,能响应 /users 的 GET 请求并返回一个字符串数组。
启动与测试
项目根目录下执行:
bash
nest start这个命令会启动 src/main.ts 里引导的应用。
如果需要在代码改动后自动重启,加 --watch 或 -w:
bash
nest start -w启动后,控制台输出类似:
[Nest] 12345 - 02/25/2025, 3:45:00 PM LOG [NestFactory] Starting Nest application...
[Nest] 12345 - 02/25/2025, 3:45:00 PM LOG [InstanceLoader] AppModule dependencies initialized
[Nest] 12345 - 02/25/2025, 3:45:00 PM LOG [InstanceLoader] UsersModule dependencies initialized
[Nest] 12345 - 02/25/2025, 3:45:00 PM LOG [RoutesResolver] AppController {/}:
[Nest] 12345 - 02/25/2025, 3:45:00 PM LOG [RouterExplorer] Mapped {/, GET} route
[Nest] 12345 - 02/25/2025, 3:45:00 PM LOG [RoutesResolver] UsersController {/users}:
[Nest] 12345 - 02/25/2025, 3:45:00 PM LOG [RouterExplorer] Mapped {/users, GET} route
[Nest] 12345 - 02/25/2025, 3:45:00 PM LOG [NestApplication] Nest application successfully started从日志能看出路由的注册过程:AppController 映射到 /,UsersController 映射到 /users。
浏览器验证
打开 http://localhost:3000/,会看到 Hello World!——这是生成项目时自带的 AppService.getHello() 的返回值。
再访问 http://localhost:3000/users,浏览器显示:
["user1","user2","user3"]curl 验证
bash
curl http://localhost:3000/users返回:
["user1","user2","user3"]如果只装了 @nestjs/cli 的全局工具,项目跑在开发模式就够了。多项目 workspace 或者需要构建产物时,用 nest build 打包到 dist/ 目录,然后直接用 node dist/main 启动。
CLI 常用命令一览
Nest CLI 的命令格式遵循 nest [command] [args] [options],大部分命令有短别名。
| 命令 | 别名 | 作用 |
|---|---|---|
nest new projectName | nest n | 创建新项目 |
nest generate module name | nest g mo name | 生成模块并自动注册 |
nest generate controller name | nest g co name | 生成控制器 |
nest generate service name | nest g s name | 生成服务 |
nest generate resource name | nest g res name | 生成完整 CRUD 资源 |
nest start | - | 启动应用 |
nest start --watch / -w | - | 监视模式启动 |
nest build | nest b | 编译应用 |
nest info | nest i | 查看已安装的 Nest 包和系统信息 |
想看某个命令的详细选项,加 --help:
bash
nest generate --help这会列出所有可用的生成器(module、controller、service、guard、pipe、interceptor 等)和它们各自的选项。
注意点
- 端口冲突:
main.ts里硬编码了 3000 端口。如果这个端口被占用,应用启动会直接报错退出。解决方法是从环境变量读取端口,或者用nest start --port 3001覆盖(这个选项在新版本 CLI 中不一定可用,具体看当前 CLI 的帮助)。 - 文件生成路径:
nest generate默认把文件生成到src/下。如果在项目根目录之外执行命令,路径会乱。所有 CLI 命令都要在项目根目录运行。 - 模块自动注册的范围:
nest generate module会自动在根模块注册,但只有用 CLI 生成的模块才会触发这个行为。手工创建的模块需要手动加imports。 nest new与包管理器的兼容:如果机器上只有 pnpm,执行nest new时却选了 npm,CLI 会尝试用 npm 安装依赖然后失败。选包管理器时确保它已安装且在 PATH 中。- 生成的测试文件:
nest generate每次都会生成.spec.ts文件。如果不需要,加--no-spec跳过。 nest startvsnpm run start:nest start是 CLI 的命令,直接调用 Nest 编译器并启动。npm run start实际上是调用package.json里的 scripts,通常是nest start。区别在于nest start --watch比npm run start:dev更直接,但start:dev可能还挂了其他钩子(比如 prebuild),具体看项目的脚本配置。
