Like @KimKen said, the problem is that, by the time that the JwtModule is instantiated the environment variables still are not loaded. However, I have a different approach to @KimKen's answer that you might also be interested in.
First of all NestJS provide a ConfigModule that load the environment variables, so you don't need to create one, unless you wish handle it different than the usual. (https://docs.nestjs.com/techniques/configuration)
Now, to solve the problem I made the module (auth.module.ts) dynamic.
In short words a dynamic module is module that receive parameters, and it depend on that input parameters for its right instantiation.(https://docs.nestjs.com/fundamentals/dynamic-modules)
The real thing going on here, is that the JwtModule is also a dynamic module because it depend on a variable for its right instantiation. So, that cause that also your module depend on parameters for its right instantiation, so make it dynamic! :).
Then your auth.module will be something like:
@Module({})
export class AuthModule {
static forRoot(): DynamicModule {
return {
imports: [
JwtModule.register({
secretOrPrivateKey: process.env.SECRET // process.env.SECRET will return the proper value
})
],
module: AuthModule
}
}
Then it will be as easy as in your app.module or where ever you load the auth.module import it through the forRoot static method.
import { ConfigModule } from '@nestjs/config';
@Module({
imports: [ConfigModule.forRoot(), AuthModule.forRoot()]
})
Note: I recommend import ConfigModule once in the app.module.ts
PD: You could make the dynamic auth.module receive a parameter in the forRoot method and in the app.module pass the environment variable process.env.SECRET
AuthModule.forRoot(process.env.SECRET)
but it seems that dynamic modules are loaded last so there is not need for that.