Im keeping my configuration in .env file when I develop my app.
This is my app.module.ts:
@Module({
imports: [
ConfigModule.forRoot({ isGlobal: true }),
TypeOrmModule.forRoot({
autoLoadEntities: true,
database: process.env.TYPEORM_DATABASE,
host: process.env.TYPEORM_HOST,
password: process.env.TYPEORM_PASSWORD,
port: (process.env.TYPEORM_PORT as unknown) as number,
type: 'postgres',
username: process.env.TYPEORM_USERNAME,
}),
AuthModule,
(...)
],
controllers: [],
providers: [],
})
export class AppModule {}
And typeorm use proper values from process.env.TYPEORM_... variables.
This is my auth.module.ts:
@Module({
providers: [JwtStrategy, (...)],
imports: [
JwtModule.register({
secret: process.env.JWT_SECRET,
(...)
}),
(...)
],
controllers: [AuthController],
})
export class AuthModule {}
And Im getting error from JwtModule, that secret can not be empty. Of course JWT_SECRET is set in .env file.
This is my jwt.strategy.ts:
@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
constructor() {
super({
secretOrKey: process.env.JWT_SECRET,
(...)
});
}
(...)
}
And here, process.env.JWT_SECRET is properly loaded.
I cant understand why my env vars are not available everywhere in my app.
If I had to take a guess, you are calling dotenv's config() method too late. In Typescript, decorators are run on module import, so anything in @Module() is run almost immediately. However, anything that is in a function call of a class method will not be run until that function is called. I'd suggest, in your main.ts file, having these as the first two lines:
import { config } from 'dotenv';
config();
This way, any .env file is read and added to process.env before anything else gets a chance to run.
The other option, as you are using the ConfigModule provided by Nest, is to use an asynchronous registration process where you use either a factory or a class instead to provide the proper configurations. In your TypeOrm config, an async registration process could look like this:
TypeOrmModule.forRootAsync({
inject: [ConfigService],
useFactory: (config: ConfigService) => ({
autoLoadEntities: true,
database: config.get<string>('TYPEORM_DATABASE'),
host: config.get<string>('TYPEORM_HOST'),
password: config.get<string>('TYPEORM_PASSWORD'),
port: config.get<number>('TYPEORM_PORT'),
type: 'postgres',
username: config.get<string>('TYPEORM_USERNAME'),
})
})
For JwtModule access to env variables you can use registerAsync, your code should be something like this:
JwtModule.registerAsync({
imports: [ConfigModule],
inject: [ConfigService],
useFactory: (config: ConfigService) => ({
secret: config.get('JWT_SECRET_KEY'),
signOptions: { expiresIn: '1h' },
}),
})
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With