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.
you should add
// eslint-disable-next-line @typescript-eslint/no-var-requires
require('dotenv').config();
into your typeormConfig file