多个私有NestJS应用间共享实体/模块的最佳方案
多NestJS应用共享TypeORM实体/模块的可行方案
先说明你提到的两个思路的实际问题:
- 跨项目复制实体文件:仅适合临时功能验证,长期维护成本极高,只要原项目调整字段、索引、表关联关系,就得手动同步多份代码,漏改一次就会触发字段映射错误、SQL执行失败这类线上问题,完全不建议长期使用
- 付费私有npm包:完全没必要,零成本的共享方案很多,根本不需要为了共享代码单独购买付费npm服务
下面按推荐优先级从高到低列可落地的方案:
方案1:Monorepo工作区共享(最优选择,零额外成本,维护成本最低)
这是目前多关联NestJS项目共享代码的主流方案,不需要发布任何npm包,直接用包管理器自带的工作区能力就能实现:
- pnpm、Yarn、npm 7及以上版本都原生支持workspace功能,不需要额外采购服务
- 参考目录结构如下:
project-root/ ├── apps/ │ ├── original-backend/ # 原有NestJS后端服务 │ └── new-backend/ # 新开发的同库NestJS应用 ├── packages/ │ └── shared-common/ # 存放公共代码 │ ├── src/ │ │ ├── entities/ # 所有共用的TypeORM实体 │ │ ├── enums/ # 公共枚举 │ │ ├── dto/ # 公共数据传输对象 │ │ └── index.ts # 统一导出所有公共内容 │ └── package.json ├── pnpm-workspace.yaml # 对应包管理工具的工作区配置文件 └── package.json
- 配置完成后,两个后端项目都可以直接在
package.json中声明工作区依赖:"@your-team/shared-common": "workspace:*",导入实体的方式和普通npm包完全一致,两边引用的是同一份代码,实体修改后两个项目实时生效,不需要手动同步或者发布版本 - TypeORM初始化时直接引入共享包导出的实体列表即可,和单项目下的写法没有区别,几乎没有额外学习成本
注意:共享包内不要写入和单项目业务强耦合的逻辑,只存放无状态的公共定义,避免两个项目的业务逻辑互相干扰。如果两个项目对同一张表有差异化的字段使用需求,可以用实体继承的方式,公共字段放共享基类,项目特有的扩展逻辑写在各自项目的派生实体里。
方案2:Git地址直接引用依赖(不想调整为Monorepo时的首选,零成本)
如果暂时不想把两个项目合并到同一仓库,不需要采购私有npm服务,所有主流包管理器都支持直接从Git仓库拉取依赖:
- 把公共实体、通用代码单独抽成一个独立的Git仓库,用团队内部现有的GitLab、Gitea或者私有GitHub仓库就行,只要开发环境、构建环境有权限拉取代码就可以
- 安装依赖时直接指定Git地址即可,示例:
pnpm add @your-team/shared-common git+ssh://git@your-internal-git/team/shared-common.git#v1.2.0 - 后续实体更新后,给公共仓库打对应tag,两个业务项目更新依赖版本即可,使用体验和普通npm包一致,没有任何额外成本
- 缺点是每次公共代码更新需要单独推送、打标签,业务项目需要手动升级依赖版本,同步效率不如Monorepo,但比手动复制文件可靠得多
方案3:本地路径直接引用(临时快速验证方案)
如果需要极短时间内跑通流程,暂时不想调整代码结构,可以直接在新项目里通过相对路径引用原项目的实体:
- 比如两个项目存放在同级目录,新项目的TypeORM配置直接写实体匹配规则:
entities: ['../original-backend/src/**/*.entity.ts'] - 缺点是耦合度极高,两个项目的本地存放路径、CI构建时的目录结构都不能随意调整,仅适合临时验证场景,长期使用不推荐
通用避坑提示
- 不管选用哪种共享方式,尽量保持两个项目的TypeORM版本、
@nestjs/typeorm适配包版本一致,避免出现装饰器兼容问题、字段映射逻辑差异 - 不要为了方便把单项目的业务逻辑塞进共享包,否则后续会出现大量逻辑耦合,改一处动两个项目,反而提升维护成本
内容的提问来源于stack exchange,提问作者pjr
相关产品推荐
相关产品推荐

