You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

NestJS引入MongooseModule后自定义env解析器报process.env未定义

问题根因

你的报错本质是环境变量加载时机和env.ts解析执行时机顺序错配,核心逻辑如下:

  • ES 模块的顶层代码会在模块第一次被导入时立即执行,你写的env对象是顶层导出的,所有字段的解析逻辑在env.ts被导入的瞬间就会全部执行,和你用不用JWT_SECRET无关。
  • 当你不添加MongooseModule相关代码时,env.ts第一次被导入是在main.ts调用app.listen的时候,此时ConfigModule已经完成.env文件的加载,process.env有完整的环境变量,解析不会报错。
  • 当你添加MongooseModule.forRoot(env.MONGO_URI)代码后,app.module.ts的导入阶段就会引用env对象,触发env.ts的解析逻辑,但此时ConfigModule.forRoot()还没有完成.env文件的加载,process.env里没有对应变量,因此直接抛出解析异常。
  • 你手动在顶部加require('dotenv').config()能正常运行,也是因为这行代码在所有模块导入前就完成了.env加载,提前给process.env赋值。

另外补充一个你的.env模板的小问题:DATABASE_PWD行缺少等号,正式使用时需要修正为DATABASE_PWD=,否则该变量无法被正常识别。

解决方案

你可以根据自己的使用习惯选任意一种方案:

方案1:提前加载dotenv

在项目入口文件main.ts的最顶部第一行添加dotenv加载逻辑,保证所有模块导入前已经完成环境变量加载:

require('dotenv').config()
// 其他所有import语句都放在这行之后
import { NestFactory } from '@nestjs/core'
// ...其余代码

方案2:改用Mongoose异步注册方式

不要在imports里直接引用env对象,改用forRootAsync异步注册Mongoose,保证ConfigModule加载完成后再读取环境变量:

@Module({
  imports: [
    ConfigModule.forRoot({
      isGlobal: true,
    }),
    MongooseModule.forRootAsync({
      useFactory: () => {
        // 这里执行的时候ConfigModule已经加载完成,env解析正常
        return {
          uri: env.MONGO_URI
        }
      }
    }),
  ],
  controllers: [AppController],
})
export class AppModule {}

方案3:直接使用Nest官方ConfigService

放弃自定义的env解析工具,改用Nest原生的ConfigService处理环境变量,完全规避执行时机问题:

// app.module.ts
MongooseModule.forRootAsync({
  useFactory: (configService: ConfigService) => ({
    uri: configService.get<string>('MONGO_URI'),
  }),
  inject: [ConfigService],
})

内容的提问来源于stack exchange,提问作者Zając

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.01 22:15:01