返回博客
NestJS@nestjs/config

NestJS 实用指南:配置管理怎么做?我们这样支持多环境切换

RaytonX
2 min read

在中大型 NestJS 项目中,配置管理是系统稳定运行的关键一环
如何优雅地加载 .env 文件?如何实现类型安全校验?如何区分开发、测试、生产环境的配置?
本篇将完整分享我们在项目中如何构建一个清晰、可靠、可扩展的配置系统。

1. 为什么配置管理很重要?

  • .env 配置混乱,环境变量被硬编码
  • 多环境切换不清晰,部署频繁出错
  • 缺少校验,配置缺失直到运行时报错
  • 多个模块依赖配置,导入重复、维护困难

我们通过 @nestjs/config 模块 + 配置加载器(Configuration Loader)+ 类型校验,构建了一套 可组合、可校验、易扩展 的配置方案。

2. 配置 ConfigService

1. 安装依赖

pnpm add @nestjs/config joi

2. 项目结构

src/
├── config/
│   ├── configuration.ts         # 配置加载器
│   ├── validation.ts            # Joi 校验规则
│   └── config.interface.ts      # 类型定义(可选)
├── app.module.ts
├── main.ts
├── .env
├── .env.development
├── .env.production
├── .env.test

3. 配置加载器 configuration.ts

集中管理 .env 中的配置项,便于类型补全与模块间复用。

// src/config/configuration.ts
export default () => ({
  port: parseInt(process.env.PORT ?? '3000', 10),
  database: {
    uri: process.env.MONGODB_URI,
  },
  jwt: {
    secret: process.env.JWT_SECRET,
    expiresIn: process.env.JWT_EXPIRES_IN ?? '1d',
  },
});

4. 配置校验 validation.ts

使用 Joi 在应用启动前强校验配置项合法性,防止运行时才暴露错误。

// src/config/validation.ts
import * as Joi from 'joi';

export const validationSchema = Joi.object({
  PORT: Joi.number().default(3000),
  MONGODB_URI: Joi.string().uri().required(),
  JWT_SECRET: Joi.string().required(),
  JWT_EXPIRES_IN: Joi.string().default('1d'),
});

5. AppModule 中引入配置模块

将配置模块设置为全局,并支持多环境 .env 文件加载。

// src/app.module.ts
import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import configuration from './config/configuration';
import { validationSchema } from './config/validation';

const getEnvFilePath = (): string[] => {
  const env = process.env.NODE_ENV;
  const base = '.env';
  const mapping: Record<string, string> = {
    production: '.env.production',
    development: '.env.development',
    test: '.env.test',
  };
  return [mapping[env ?? 'development'], base];
};

@Module({
  imports: [
    ConfigModule.forRoot({
      isGlobal: true,
      load: [configuration],
      validationSchema,
      envFilePath: getEnvFilePath(),
    }),
    // ...其他模块
  ],
})
export class AppModule {}

3. 使用配置 ConfigService

在任何服务或模块中使用 ConfigService 获取类型安全的配置。

import { Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';

@Injectable()
export class AuthService {
  constructor(private readonly configService: ConfigService) {}

  getJwtSecret(): string {
    return this.configService.get<string>('jwt.secret');
  }
}

启动项目时使用正确的环境变量

NODE_ENV=production node dist/main.js

4. Kubernetes 注入环境变量

生产环境使用 Kubernetes 注入的环境变量, 禁止 .env.production 文件被打包进 Docker 镜像。

1. 修改 getEnvFilePath

const getEnvFilePath = (): string[] => {
  const env = process.env.NODE_ENV;
  const base = '.env';
  const mapping: Record<string, string> = {
    development: '.env.development',
    test: '.env.test',
  };
  return env === 'production' ? undefined : [mapping[env ?? 'development'], base];
};

2. K8s 配置

  1. configmap

    # configmap.yaml
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: myapp-config
    data:
      PORT: "3000"
      DATABASE_URL: "postgres://user:pass@host:5432/db"
    
  2. deployment

    # deployment.yaml
    spec:
      containers:
        - name: myapp
          image: your-image:tag
          envFrom:
            - configMapRef:
                name: myapp-config
    

如果你也在用 NestJS 构建中后台项目,不妨参考这套方式,统一你的配置管理逻辑,提升代码的健壮性与可维护性。