config
config copied to clipboard
Using ConfigModule.forFeature with the same property names in different feature configurations results in properties being overridden
Is there an existing issue for this?
- [X] I have searched the existing issues
Current behavior
Suppose we have the following .env
:
APPLE_API_URL = 'http://apples.com/api/v1'
ORANGE_API_URL = 'http://oranges.com/api/v1'
There are two generated library modules:
AppleModule
import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { AppleService } from './apple.service';
import { appleConfig } from './config';
@Module({
imports: [ConfigModule.forFeature(appleConfig)],
providers: [AppleService],
exports: [AppleService],
})
export class AppleModule {}
appleConfig
import { AppleConfig } from './interfaces';
export const appleConfig = (): AppleConfig => ({
apiUrl: process.env.APPLE_API_URL,
});
OrangeModule
import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { orangeConfig } from './config';
import { OrangeService } from './orange.service';
@Module({
imports: [ConfigModule.forFeature(orangeConfig)],
providers: [OrangeService],
exports: [OrangeService],
})
export class OrangeModule {}
orangeConfig
import { OrangeConfig } from './interfaces';
export const orangeConfig = (): OrangeConfig => ({
apiUrl: process.env.ORANGE_API_URL,
});
The idea here is that I want to shorten ConfigService property names from things like appleApiUrl
and orangeApiUrl
to simple apiUrl
in each feature's ConfigModule registration.
In this minimal reproduction, the services are simply logging what each module's ConfigService is getting for apiUrl
.
apple.service.ts
import { Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { AppleConfig } from './config';
@Injectable()
export class AppleService {
public constructor(
private readonly configService: ConfigService<AppleConfig>,
) {}
public doAppleThing(): void {
const apiUrl = this.configService.get('apiUrl');
console.log(apiUrl);
}
}
orange.service.ts
import { Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { OrangeConfig } from './config';
@Injectable()
export class OrangeService {
public constructor(
private readonly configService: ConfigService<OrangeConfig>,
) {}
public doOrangeThing(): void {
const apiUrl = this.configService.get('apiUrl');
console.log(apiUrl);
}
}
The app's controller has GET routes apple
and orange
that simply call the respective service's method.
Making a request to http://localhost:3000/orange
logs the expected value:
'http://oranges.com/api/v1'
However, making a request to http://localhost:3000/apple
also logs the "orange API URL" rather than the "apple API URL" as expected:
'http://oranges.com/api/v1'
This tells me that, since OrangeModule
is imported after AppleModule
in AppModule
, OrangeModule
's ConfigModule.forFeature
registration is overriding the value of apiUrl
in AppleModule
's configuration even though they should be separate registrations.
Minimum reproduction code
https://github.com/IRCraziestTaxi/nestjs-config-same-prop-name-undefined
Steps to reproduce
See "Current behavior" section above and minimal reproduction.
Expected behavior
Since the two feature modules' ConfigModule.forFeature
registrations are for separate modules using a forFeature
call, each module's configuration for apiUrl
should be unique per the config factory passed into forFeature
.
Package version
2.2.0
NestJS version
9.1.4
Node.js version
18.3.0
In which operating systems have you tested?
- [X] macOS
- [ ] Windows
- [ ] Linux
Other
No response