大家好 👋,我是 Moment,目前正在使用 Next.js、NestJS、LangChain 开发 DocFlow。这是一个面向 AI 场景的协同文档平台,集成了基于
Tiptap的富文本编辑、NestJS后端服务、实时协作与智能化工作流等核心模块。在这个项目的持续打磨过程中,我积累了不少实战经验,不只是
Tiptap的深度定制、编辑器性能优化和协同方案设计,也包括前端工程化建设、React 源码理解以及复杂项目架构实践。如果你对 AI 全栈开发、文档编辑器、前端工程化或者 React 源码相关内容感兴趣,欢迎添加我的微信
yunmz777一起交流。觉得项目还不错的话,也欢迎给 DocFlow 点个 star ⭐

很多人第一次写 Node.js 服务端,都会先从 Express、Koa 开始。这个选择没有问题。它们轻量、直接、上手快,很适合做原型验证、小型接口服务,或者个人练手项目。
可一旦项目进入真实业务环境,要衡量的就不只是接口能不能先跑通,还包括项目能不能持续演进、团队能不能长期协作、几个月后代码还能不能被人看懂、改动和扩展。
这正是很多团队后来转向 NestJS 的原因。
NestJS 的核心价值不在于语法看起来是不是更高级,而在于把后端从能跑通,往能长期维护再推一步。也可以把它看成一套更强调工程组织、协作边界和系统演进能力的 Node.js 后端框架。
Node.js 服务端开发真正难的不是写接口
刚开始学服务端时,很多人会觉得最难的是路由、数据库、鉴权、缓存这些具体功能。可项目做久了就会发现,单个功能本身通常都不算最难。真正难的是,当功能越来越多、业务越来越复杂之后,整个系统还能不能保持清晰。
项目早期往往感受不到这种压力。接口少、开发者少、调用链也短,大家靠记忆和默契就能把事情推进下去。可只要业务开始增长,下面这些问题通常都会陆续冒出来:
- 目录结构没有统一标准,不同人按不同习惯组织代码
- 路由、参数校验、业务逻辑、数据库操作揉在一起,职责边界越来越模糊
- 鉴权、日志、异常处理、缓存这类公共逻辑散落在各处,排查问题很费劲
- 新成员接手项目时,先要理解团队内部那套没写成文档的约定
- 模块之间的依赖关系变得混乱,改一个地方容易牵动一串逻辑
- 代码越积越多,团队越来越不敢重构,只能在旧结构上继续叠补丁
所以 Node.js 服务端开发真正难的地方,往往不是写不出来,而是越写越乱。
这类混乱并不会在第一天出现。它通常发生在项目已经做出一定成果之后,所以也更危险。因为系统明明还能运行,但维护成本已经在悄悄上升。
Express、Koa 为什么灵活却容易失控
Express、Koa 的强项是灵活。它们给你的更多是底层能力,而不是强约束的工程结构。你可以自由决定目录怎么分、依赖怎么管理、参数怎么校验、异常怎么统一处理、权限怎么接入。
这种自由在项目初期非常舒服。你几乎不会被框架束缚,想到什么就能快速搭起来,开发效率也很高。
但自由本身不会自动变成秩序,它还意味着你必须自己完成本该由框架兜底的工程设计。
也就是说:
- 框架不替你做架构决策
- 团队必须自己制定规范
- 规范能不能真正落地,很依赖成员经验和执行力
- 只要执行稍有偏差,代码风格和分层方式就会开始分裂
举个非常常见的例子。同样是创建用户接口,有的人把参数校验写在路由层,有的人写在中间件里,有的人写在 Service 里。有人直接把数据库报错原样抛出,有人手动包装统一响应,还有人把一部分逻辑写在工具函数里。每一种写法单看都能工作,放在一起却会让项目越来越难读、越来越难改。
所以问题不在于 Express、Koa 不够好,而在于它们更适合这些场景:
- 团队规模小,成员对架构理解比较一致
- 项目边界清晰,生命周期较短,复杂度可控
- 团队愿意自己长期维护一整套工程规范
如果这些条件不成立,原本的灵活性就很容易演变成失控。
NestJS 想解决的是工程组织问题
NestJS 并不是要替代 Node.js,也不是否定 Express、Koa。从底层实现上看,它本身就可以运行在这些能力之上。它真正做的,是在底层 HTTP 能力之上,再提供一层更明确的工程化组织方式。
换句话说,NestJS 想解决的不只是怎样把一个接口写出来,而是下面这些更接近长期项目本质的问题:
- 如何让目录结构和职责边界从一开始就更清晰
- 如何把
Controller、Service、Module、数据访问层分开 - 如何用统一方式处理校验、鉴权、日志、异常、缓存这类横切逻辑
- 如何让多人协作时拥有共同术语和共同写法
- 如何让项目随着规模增长,依然保持可读、可测、可扩展
所以 NestJS 提供的价值,不是某一个孤立的功能点,而是一套比较完整的后端组织方法。
很多团队在项目做大之后不得不自己补上的工程约定,NestJS 在框架层面先替你铺了一层默认结构。
NestJS 的核心思路是什么
初学者刚接触 NestJS 时,最容易把注意力放在装饰器语法上,比如 @Controller()、@Get()、@Injectable()。这些语法当然重要,但它们不是重点。重点是 NestJS 借这些语法表达出一套明确的系统分工。
从整体上看,NestJS 的思路可以浓缩成几件事:
- 用
Module组织功能边界 - 用
Controller处理请求入口和响应出口 - 用
Service承载业务逻辑 - 用依赖注入管理对象之间的协作关系
- 用
Pipe、Guard、Interceptor、异常过滤器处理公共横切逻辑
这意味着你不需要在每个项目里都重新争论控制器写到哪一层、校验放哪里、日志在哪里接、异常怎么统一处理,框架已经给出了比较成熟的落点。
很多团队在不用 NestJS 时,最终也会慢慢形成类似规范。区别在于,那种规范通常靠口头约定、代码评审和团队经验去维持,成本高,也容易随着人员流动而松动。NestJS 做的事情,本质上是把这些容易反复争论的约定沉淀成默认结构。
从自由拼装到统一组织
没有统一结构时,路由、中间件和业务代码容易堆在一起,边界变糊,协作和维护成本会跟着涨。NestJS 用模块化、依赖注入,再配合 Pipe、Guard、Interceptor 等横切能力,把职责边界和演进节奏相对固定下来。

缺少约定时,常见顺序是功能先快速往上堆,结构一开始就比较混,职责边界慢慢说不清,谁该动哪一块也不明朗,团队对齐和返工会变多,到了维护和重构阶段,改动容易牵一片、风险也跟着上去。换成 NestJS 默认那套组织方式,目录和依赖会有比较固定的落点,模块边界和分层更清晰,校验、鉴权、异常这类横切逻辑可以统一接入,后续扩展更稳,协作和测试也更好接。
什么叫工程化后端框架
所谓工程化后端框架,就是那种不只关心功能能不能实现,也关心项目能不能长期稳定演进的后端框架,通常会具备下面这些特点:
- 有明确的模块划分方式
- 有清晰的依赖组织和职责边界
- 能统一处理日志、鉴权、异常、缓存这类公共问题
- 便于测试、扩展、重构和多人协作
- 当业务规模增长时,代码结构不会迅速失控
NestJS 正是沿着这个方向设计的。它吸收了很多成熟后端框架里的思想,比如模块化、依赖注入、面向切面式的横切处理思路,再结合 TypeScript 和装饰器能力,把这些思想落到 Node.js 的开发体验里。
所以选择 NestJS,本质上不是单纯选择某个路由库,而是在选择一种更偏系统化、组织化的后端开发方式。
NestJS 给团队带来的直接收益
如果只把 NestJS 当成一个写接口的框架,会低估它。它更大的价值,往往体现在团队和项目生命周期上。
在真实项目里,它常见的收益大致有这些:
- 新成员更容易看懂项目结构,功能位置和依赖关系更容易定位
- 控制器、服务、模块之间分工更清楚,代码职责更容易收敛
- 参数校验、权限控制、异常处理、日志记录可以通过统一机制接入
- 测试时更容易替换依赖、隔离模块、编写单元测试和集成测试
- 当项目逐步引入缓存、队列、定时任务、文件上传、消息通信时,整体结构更容易承接
这些收益乍一看不如一条性能曲线那么直观,但它们常常决定了一个项目半年后是越来越稳,还是越来越脆。
对团队来说,NestJS 相当于提前做了一部分工程设计。这样大家能把更多精力放在业务本身,而不是反复争论项目应该怎样分层、怎样约束。
什么时候更适合选择 NestJS
NestJS 不是所有 Node.js 项目的唯一答案,但在下面这些场景里,它通常很合适:
- 你做的是一个会持续演进的业务系统,而不是一次性 demo
- 项目会有多人协作,希望统一开发方式和代码结构
- 业务中会逐步引入鉴权、缓存、队列、定时任务、上传、消息通信等能力
- 你希望系统在扩张过程中依然保持清晰分层
- 你希望后续测试、重构、扩展的成本更可控
尤其是在中后台系统、管理平台、企业服务、平台型业务里,NestJS 往往比在 Express 或 Koa 上从零搭一整套规范更省心。
什么时候未必一定要用 NestJS
说推荐 NestJS,并不意味着所有项目都该上它。对一些场景来说,它确实会显得偏重。
比如下面这些情况,就未必一定需要:
- 只是写一个非常小的 demo
- 只做几个简单接口,生命周期也不长
- 团队规模很小,而且已经有一套稳定熟悉的工程规范
- 当前目标是快速验证需求,而不是先搭完整项目骨架
原因很简单。NestJS 的收益通常会在项目逐渐复杂之后越来越明显。项目越复杂,它越有价值。项目越简单,它的前期结构成本就越容易显得偏高。
为了更直观一些,可以简单对比一下:
| 场景 | 更偏向的选择 |
|---|---|
| 个人练手、小型原型、快速验证 | Express、Koa 更轻 |
| 多人协作、中长期业务系统 | NestJS 更稳 |
| 规范成熟、边界清晰的小团队项目 | 视团队习惯决定 |
| 后续会持续扩展能力的系统 | NestJS 更合适 |
这个判断没有绝对标准,但很实用的一条是,若你眼下最看重先把东西跑通,更轻的底层框架往往更合适,一旦你开始担心以后会不会越来越难改,NestJS 通常就落到合适的选型区间里了。
初学者理解 NestJS 时最容易出现的误区
第一次接触 NestJS,常见误区主要有三个。
第一,把它理解成一堆装饰器语法。
其实装饰器只是表面形式。真正需要理解的,是它背后的分层思想、模块边界和依赖管理方式。
第二,把它理解成比 Express 更复杂的替代品。
更准确地说,NestJS 不是单纯追求更复杂,而是在用更明确的结构换取更好的可维护性。它增加的是前期组织成本,换来的是后期演进空间。
第三,把它理解成只要上了 NestJS,项目就一定会变整洁。
框架只能提供更好的骨架,不能代替团队做所有设计。模块怎么拆、边界怎么划、命名是否清晰、业务是否收敛,这些仍然需要开发者自己做好。
所以学习 NestJS 时,真正重要的不是先记住多少装饰器,而是先建立一个整体认知:
- 它为什么出现
- 它解决了什么长期问题
- 它通过哪些机制维持结构稳定
一旦这个认知建立起来,后面再学 Controller、Module、Provider、Pipe、Guard、Interceptor,理解会顺畅很多。
小结
选择 NestJS,本质上不是在挑一个更炫的 Node.js 框架,而是在选一种更适合长期项目的组织方式。
如果你的目标只是把几个接口快速跑起来,Express、Koa 依然是很好的选择。可如果你更在意系统的可维护性、可协作性和后续扩展能力,那么 NestJS 提供的模块化、依赖注入和统一处理机制,往往会在项目越做越大时显现出明显价值。
也可以把选型说得更直白一点,小项目先追速度,复杂项目必须重视秩序,NestJS 的作用就是在 Node.js 服务端里尽量把这份秩序提前搭起来。
接下来会拆开讲 NestJS 的核心组成部分,从最基础的认知和项目结构入手,看它怎样组织一个后端应用。