约定优于配置的 companion 文件
users.controller.ts → users.controller.docs.ts。和 Nest 已经在用的 *.controller.spec.ts 是同一套模式。
带 CI 门禁的 CLI
check、coverage --min、lint 和 patch-spec。文档缺失时直接让构建失败。
自动类型推断
接口、class-validator 和 @HttpCode() 无需额外装饰器即可变成 OpenAPI schema。
AI 优先的 Docfy UI
每个端点都带 Copy for AI 按钮的参考界面,特别适合粘贴进 LLM。
docfy-ui:AI 优先的参考查看器
nestjs-docfy 组装出的 OpenAPI spec,同样也是 docfy-ui 渲染的内容,不需要额外配置,用的是同一份事实来源。
- Copy for AI:一份确定性生成、可直接喂给 LLM 的端点摘要,而不是带 $ref 的原始 JSON 转储
- ⌘K 即时搜索所有端点
- 每个端点完整的请求/响应细节,直接从 spec 生成






实际用起来是什么样
之前:一个被装饰器淹没的控制器。之后:只剩路由本身,文档就在旁边的 companion 文件里。
users.controller.ts
@WithDocs()
@Controller('users')
export class UsersController {
constructor(private readonly users: UsersService) {}
@Get(':id')
findOne(@Param('id') id: string) {
return this.users.findOne(id);
}
}users.controller.docs.ts
import { docs } from 'nestjs-docfy';
import { ApiTags, ApiOperation, ApiResponse } from '@nestjs/swagger';
import { UsersController } from './users.controller';
docs(UsersController, {
classDecorators: [ApiTags('users')],
methods: {
findOne: [
ApiOperation({ summary: 'Get user by id' }),
ApiResponse({ status: 200, description: 'OK', type: UserDto }),
ApiResponse({ status: 404, description: 'User not found' }),
],
},
});只在启动时运行,零请求时开销和内联装饰器生成完全相同的 OpenAPI 输出Companion 文件约定,就像 *.spec.ts 一样
没有猴子补丁,没有运行时代理
只是恰到好处的时机,加上 Reflect 元数据。
01
写 companion 文件
users.controller.docs.ts 调用 docs(UsersController, { ... }),普通的 Swagger 装饰器,只是搬到了另一个文件里。
02
启动时被发现
DocfyModule.forRoot() 通过命名约定找到它,并在 SwaggerModule.createDocument() 运行之前,把 Reflect 元数据写到控制器的方法上。
03
完全一致的 OpenAPI 输出
SwaggerModule 看到的元数据,和装饰器直接写在控制器上时完全一样。