Skip to content

NestJSで環境変数をアプリケーションモジュールで使用する方法

問題

NestJSアプリケーションでデータベース接続情報を環境変数から読み込みたい場合、app.module.tsファイル内で.env変数を直接使用しようとすると問題が発生します。元のコードではハードコーディングされた接続文字列が動作していましたが、環境変数を使用するように変更すると接続に失敗します。

元の動作していたコード:

typescript
@Module({
  imports: [
    MongooseModule.forRoot(`mongodb+srv://myusername:mypassword@myhost.net?retryWrites=true&w=majority&db=dbname`, { useNewUrlParser: true, dbName: 'dbname' }),
    ProductModule,
    CategoryModule,
  ],
})

環境変数を使用した非動作コード:

typescript
@Module({
  imports: [
    ConfigModule.forRoot({ envFilePath: `${process.env.NODE_ENV}.env` }),
    MongooseModule.forRoot(`mongodb+srv://${ConfigModule.get('DB_USER')}:${ConfigModule.get('DB_PASS')}@myhost.net?retryWrites=true&w=majority&db=dbname`, { useNewUrlParser: true, dbName: 'dbname' }),
    ProductModule,
    CategoryModule,
  ],
})

解決策

方法1: ConfigModuleとforRootAsyncの使用(推奨)

最も一般的で推奨される方法は、ConfigModuleとデータベースモジュールの非同期設定(forRootAsync)を使用する方法です。

typescript
import { Module } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { MongooseModule } from '@nestjs/mongoose';

@Module({
  imports: [
    ConfigModule.forRoot({
      isGlobal: true,
      envFilePath: `.env.${process.env.NODE_ENV}`
    }),
    MongooseModule.forRootAsync({
      imports: [ConfigModule],
      useFactory: async (configService: ConfigService) => ({
        uri: configService.get<string>('MONGODB_URI'),
      }),
      inject: [ConfigService],
    }),
    ProductModule,
    CategoryModule,
  ],
})
export class AppModule {}

INFO

環境変数ファイルは通常、.envという名前ですが、NODE_ENV環境変数に基づいて異なるファイルを使用できます(例: .env.development, .env.production)。

方法2: データベース専用モジュールの作成

データベース接続を分離したモジュールを作成する方法です。

database.module.ts:

typescript
import { Module } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { MongooseModule } from '@nestjs/mongoose';

@Module({
  imports: [
    MongooseModule.forRootAsync({
      imports: [ConfigModule],
      useFactory: async (configService: ConfigService) => ({
        uri: configService.get<string>('MONGODB_URI'),
        dbName: configService.get<string>('DB_NAME'),
      }),
      inject: [ConfigService],
    }),
  ],
  exports: [MongooseModule],
})
export class DatabaseModule {}

app.module.ts:

typescript
import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { DatabaseModule } from './database/database.module';
import { ProductModule } from './product/product.module';
import { CategoryModule } from './category/category.module';

@Module({
  imports: [
    ConfigModule.forRoot({
      isGlobal: true,
      envFilePath: `.env.${process.env.NODE_ENV}`
    }),
    DatabaseModule,
    ProductModule,
    CategoryModule,
  ],
})
export class AppModule {}

方法3: 環境変数の直接使用

シンプルなケースでは、環境変数を直接使用することもできます。

typescript
import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { MongooseModule } from '@nestjs/mongoose';

@Module({
  imports: [
    ConfigModule.forRoot(),
    MongooseModule.forRootAsync({
      useFactory: () => ({
        uri: process.env.MONGODB_URI,
      }),
    }),
  ],
})

WARNING

この方法はシンプルですが、ConfigServiceを使用した方法に比べて型安全性や設定の柔軟性が低くなります。

環境変数の設定

.envファイルの例:

env
NODE_ENV=development
MONGODB_URI=mongodb+srv://username:password@host.net/dbname?retryWrites=true&w=majority
DB_USER=username
DB_PASS=password
DB_HOST=host.net
DB_NAME=dbname

package.jsonのスクリプト設定

環境に応じて異なる環境変数ファイルを読み込むためのスクリプト設定:

json
{
  "scripts": {
    "start:dev": "cross-env NODE_ENV=development npm run start",
    "start:prod": "cross-env NODE_ENV=production npm run start",
    "start:local": "cross-env NODE_ENV=local npm run start"
  }
}

TIP

cross-envパッケージを使用すると、異なるOS間で環境変数の設定を統一できます。インストールにはnpm install -D cross-envを実行してください。

トラブルシューティング

ConfigModuleが環境変数を読み込まない場合

ConfigModule.forRoot()を複数回呼び出すことで解決する場合があります:

typescript
@Module({
  imports: [
    ConfigModule.forRoot(), // 最初に環境変数を読み込む
    ConfigModule.forRoot({ // 設定を適用する
      isGlobal: true,
      envFilePath: `.env.${process.env.NODE_ENV}`
    }),
    // 他のモジュール
  ],
})

環境変数がundefinedの場合

  1. 環境変数ファイルが正しい場所にあることを確認
  2. 環境変数名が正しいことを確認
  3. NODE_ENVが正しく設定されていることを確認

まとめ

NestJSで環境変数をアプリケーションモジュールで使用するには、ConfigModuleと非同期設定(forRootAsync)を組み合わせる方法が最も効果的です。データベース接続を専用モジュールに分離することで、コードの保守性とテストの容易性を向上させることができます。

適切な環境変数管理は、アプリケーションのセキュリティと設定の柔軟性を確保する上で重要です。本番環境では、環境変数の管理にさらに注意を払い、機密情報がコードベースにハードコーディングされないようにしましょう。