Search code examples
postgresqlnestjstypeormnestjs-config

NestJS .env variables undefined from AppModule


I set up a NestJS project that uses TypeORM with Postgres - Docker. TypeORM successfully connects to my Postgres DB when I hardcode the connection values into the config, but not when using environment variables.

To test whether .env vars get read at all, I tried console.log-ing them from main.ts and the values were read without issue, but for some reason replacing the hard coded values with ENV vars results in the error: SASL: SCRAM-SERVER-FIRST-MESSAGE: client password must be a string for the DB connection

Below is my TypeORM config where the values should be read

import { registerAs } from '@nestjs/config';
import { join } from 'path';
import { DataSourceOptions } from 'typeorm';

export const typeormConfig = registerAs(
  'typeorm',
  (): DataSourceOptions => ({
    type: 'postgres',
    host: process.env.POSTGRES_HOST,
    port: +process.env.POSTGRES_PORT,
    username: process.env.POSTGRES_USERNAME,
    password: process.env.POSTGRES_PASSWORD,
    database: process.env.POSTGRES_DATABASE,
    synchronize: false,
    logging: false,
    entities: [],
    migrations: [join(__dirname, './migrations/**/*.{ts,js}'), join(__dirname, './seeds/**/*.{ts,js}')],
  }),
);

Here is my app.module.ts

import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { TypeOrmModule, TypeOrmModuleAsyncOptions, TypeOrmModuleOptions } from '@nestjs/typeorm';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { configsArray } from './config';
import { LoggerModule } from 'nestjs-pino';

@Module({
  imports: [
    ConfigModule.forRoot({ load: configsArray }),
    TypeOrmModule.forRootAsync({
      inject: [ConfigService],
      imports: [ConfigModule],
      useFactory: (configService: ConfigService): TypeOrmModuleAsyncOptions =>
        configService.get<TypeOrmModuleOptions>('typeorm'),
    }),
    LoggerModule.forRootAsync({
      imports: [ConfigModule],
      inject: [ConfigService],
      useFactory: async (config: ConfigService) => config.get('pino'),
    }),
  ],
  controllers: [AppController],
  providers: [],
})
export class AppModule {}

And main.ts where the password is successfully logged

import { INestApplication, ValidationPipe, ValidationPipeOptions, Logger } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { NestFactory } from '@nestjs/core';
import { LoggerErrorInterceptor, Logger as Pino } from 'nestjs-pino';
import { AppDataSource } from 'ormconfig';
import { AppModule } from './app.module';
import { TypeOrmExceptionFilter } from './shared/exceptions/type-orm-exception.filter';
import { TimeoutInterceptor } from './shared/interceptors/timeout.interceptor';

async function bootstrap() {
  const app = await NestFactory.create(AppModule, { cors: true });
  console.log(process.env.POSTGRES_PASSWORD);
  const configService: ConfigService = app.get(ConfigService);
  const PORT: string = configService.get('server.port');
  const HOST: string = configService.get('server.host');
  const VALIDATION_PIPE: ValidationPipeOptions = configService.get('validation-pipe');

  app.useGlobalPipes(new ValidationPipe(VALIDATION_PIPE));
  app.useGlobalFilters(new TypeOrmExceptionFilter());
  app.useGlobalInterceptors(new LoggerErrorInterceptor());
  app.useGlobalInterceptors(new TimeoutInterceptor());
  app.useLogger(app.get(Pino));
  const logger: Logger = new Logger('main.ts');

  AppDataSource.initialize()
  .then(() => {
    console.log('Connected to Data Source');
  })
  .catch((err) => {
    console.error('Error during Data Source initialization', err);
  });

  await app.listen(PORT, HOST);
  logger.log(`Server has been started on HOST: ${HOST}, PORT: ${PORT}`);
}
bootstrap();

So I can confirm that I am not using the wrong DB connection values and .env vars do get read from other files.

I would appreciate any help on what might be the issue here.


Solution

  • you should add

    // eslint-disable-next-line @typescript-eslint/no-var-requires

    require('dotenv').config(); into your typeormConfig file