NestJS中MikroORM配置文件无法读取环境变量问题
问题原因
你的问题出在模块加载顺序上:database.config.ts里的代码在Nest的ConfigModule初始化之前就被执行了。当AppModule导入config对象时,Node会先加载database.config.ts并执行其中的代码,这时候ConfigModule还没来得及把环境变量注入到process.env中,所以process.env.DB_PASSWORD是undefined。而控制器等文件是在模块初始化完成后才被实例化的,这时候环境变量已经加载完成,所以能正常读取。
解决方案
推荐使用MikroORM的异步配置方式,借助Nest的依赖注入确保ConfigService已经加载了环境变量,具体步骤如下:
方案1:直接在AppModule中使用异步配置
修改app.module.ts,替换MikroOrmModule.forRoot(config)为异步配置:
import { ConfigModule, ConfigService } from '@nestjs/config'; import { Module } from '@nestjs/common'; import { MikroOrmModule } from '@mikro-orm/nestjs'; import { MySqlDriver } from '@mikro-orm/mysql'; import { BaseRepository } from 'src/libs/db/base-repository.repository'; import { Migrator } from '@mikro-orm/migrations'; // ...其他导入 @Module({ imports: [ ConfigModule.forRoot({ isGlobal: true }), // 设为全局模块,避免重复导入 MikroOrmModule.forRootAsync({ useFactory: (configService: ConfigService) => ({ entities: ['./dist/core/entities'], entitiesTs: ['./src/core/entities/*.*'], dbName: 'invoice-app-be', driver: MySqlDriver, entityRepository: BaseRepository, password: configService.get<string>('DB_PASSWORD'), migrations: { tableName: 'mikro_orm_migrations', path: './lib/db/migrations/', allOrNothing: true, }, extensions: [Migrator], }), inject: [ConfigService], // 注入ConfigService }), ], controllers: [AppController], providers: [ AppService, UserService, InvoiceService, LineItemService, BillToService, BillFromService, ], }) export class AppModule {}
这种方式不需要单独的database.config.ts,直接把配置逻辑放在useFactory函数里,useFactory会在ConfigService初始化完成后执行,确保能拿到环境变量。
方案2:保留配置文件,改为函数式配置
如果想保留单独的配置文件,可以把database.config.ts改成接受ConfigService的函数:
import { Migrator } from '@mikro-orm/migrations'; import { MySqlDriver } from '@mikro-orm/mysql'; import { BaseRepository } from 'src/libs/db/base-repository.repository'; import { ConfigService } from '@nestjs/config'; export const getMikroOrmConfig = (configService: ConfigService) => ({ entities: ['./dist/core/entities'], entitiesTs: ['./src/core/entities/*.*'], dbName: 'invoice-app-be', driver: MySqlDriver, entityRepository: BaseRepository, password: configService.get<string>('DB_PASSWORD'), migrations: { tableName: 'mikro_orm_migrations', path: './lib/db/migrations/', allOrNothing: true, }, extensions: [Migrator], });
然后在app.module.ts中调用这个函数:
import { ConfigModule, ConfigService } from '@nestjs/config'; import { Module } from '@nestjs/common'; import { MikroOrmModule } from '@mikro-orm/nestjs'; import { getMikroOrmConfig } from './configs/database.config'; // ...其他导入 @Module({ imports: [ ConfigModule.forRoot({ isGlobal: true }), MikroOrmModule.forRootAsync({ useFactory: (configService: ConfigService) => getMikroOrmConfig(configService), inject: [ConfigService], }), ], // ...控制器和提供者 }) export class AppModule {}
备选方案:手动加载环境变量(不推荐)
如果不想用异步配置,也可以在database.config.ts顶部手动加载.env文件:
import 'dotenv/config'; // 手动加载.env import { Migrator } from '@mikro-orm/migrations'; // ...其他导入 console.log(process.env.DB_PASSWORD) // 现在能获取到值 export const config = { // ...原配置内容 };
但这种方式可能和ConfigModule的配置冲突(比如自定义env路径),所以仅作为备选。
内容的提问来源于stack exchange,提问作者Daniel Benisti
相关产品推荐
相关产品推荐

