Dotenvx 配置示例

Dotenvx 配置示例

基础配置示例

.env (开发环境默认配置)

# 应用配置
NODE_ENV=development
PORT=3000
APP_NAME=MyApp
APP_VERSION=1.0.0

# 数据库配置
DB_HOST=localhost
DB_PORT=5432
DB_NAME=myapp_dev
DB_USER=developer
DB_PASSWORD=dev123

# Redis 配置
REDIS_HOST=localhost
REDIS_PORT=6379
REDIS_PASSWORD=

# API 配置
API_BASE_URL=http://localhost:3000/api
JWT_SECRET=dev-secret-key
JWT_EXPIRES_IN=24h

# 第三方服务
STRIPE_PUBLISHABLE_KEY=pk_test_...
STRIPE_SECRET_KEY=sk_test_...
SENDGRID_API_KEY=SG.test...

# 日志配置
LOG_LEVEL=debug
LOG_FORMAT=combined

# 功能开关
FEATURE_NEW_UI=true
FEATURE_ANALYTICS=false

.env.production (生产环境加密配置)

#/-------------------[DOTENV_PUBLIC_KEY]--------------------/
#/            public-key encryption for .env files          /
#/       [how it works](https://dotenvx.com/encryption)     /
#/----------------------------------------------------------/
DOTENV_PUBLIC_KEY_PRODUCTION="026d4945b6513baec60f68b207f203ba534fb54d2b0c9952557d240815e42a7d83"

# 应用配置
NODE_ENV="encrypted:BKzfW56VHobMDtfq+iU+MsjVlPDdiKYoJmKLMlUKzsds5dHWjY+GcKbUx7V54jX21kVa6kuBcINNmP/DwXZA2VSb6q8zhMU/Go59aQWqmoqip6jB8DTxc8GjxUF4lWO3PLWJqk8="
PORT="encrypted:BGcRf5bK/mChGEqT1MZ8hUbMm3hhtuW9NVGkHtl7KRwqbSKnVcGIDs9T61u77DlyNlYcF1BlLCw9HPmbRQ0nFvLOCZc6r42iRE4OyJw9mu61OjlWQfEl5Z1NrjZw5g0d1tp8New="
APP_NAME="encrypted:BBrXv55qxgA19sEqqNnZzS/C0WguVk6ROQmfxnGhBhafLoc0XwpKprk/J3hJCVq7s45WyBSXGUz9U9rHxCBeVkl27WFzzgZkDewX0gBLt+Cc37K0EVU2hZ1GPbax5mzpI5Jwwi65be6+"

# 数据库配置
DB_HOST="encrypted:BMO83g2fEtr66gcFvUs2+/ZuccCQuBbZwSW3JfCLvoUiACmusxCbTfG2dvc2LxenPhUtgWapO8f9BCcBVAcTnMcrd3kndvk+acWytRjIWRUvsSezdD340/OT5EQgbqJtwXfuRz0i2t8PVA=="
DB_PORT="encrypted:BGcRf5bK/mChGEqT1MZ8hUbMm3hhtuW9NVGkHtl7KRwqbSKnVcGIDs9T61u77DlyNlYcF1BlLCw9HPmbRQ0nFvLOCZc6r42iRE4OyJw9mu61OjlWQfEl5Z1NrjZw5g0d1tp8New="
DB_NAME="encrypted:BL0icNnZh6InVmymJBCX6MuL6cwgVc4v1ua1g1XONlV7nkzzHHHpnZN3khx7+ld15bd88EtV4DfqUV2eJ/HJwu0/5F1MH+PAisYSRxBQo8I9AHly2sRsonBm3Bji+DslcC4D7b7wLTBlfCw="
DB_USER="encrypted:BBrXv55qxgA19sEqqNnZzS/C0WguVk6ROQmfxnGhBhafLoc0XwpKprk/J3hJCVq7s45WyBSXGUz9U9rHxCBeVkl27WFzzgZkDewX0gBLt+Cc37K0EVU2hZ1GPbax5mzpI5Jwwi65be6+"
DB_PASSWORD="encrypted:BC8aRBQ/Q2YMPjJayggqVN8skqTtxtXFgYA0e8/Ud/Jcez2Daukr6edBmEWQdz/Lu91casaW6CkkCvLSQkPvNpmgYqFB4BKHTUDowX/KEDvVI6CU5Vt478VF5dqHbvPIoKKtBe+4FNXlk5O96A=="

# Redis 配置
REDIS_HOST="encrypted:BMVEIPBGe9xkELFb48KQJPxxnTkUGhsonAU4ug5ca9E5eD/MZimkoQrf/3cb9nhazwfTbScLgeGGr/Jhj4DV7Xpz45XEEFWrPXy1Yi93zWLaJ4XYBHwCke3b4XCbh7jV4uL3WWFjI757yTIS6ilD"
REDIS_PORT="encrypted:BGcRf5bK/mChGEqT1MZ8hUbMm3hhtuW9NVGkHtl7KRwqbSKnVcGIDs9T61u77DlyNlYcF1BlLCw9HPmbRQ0nFvLOCZc6r42iRE4OyJw9mu61OjlWQfEl5Z1NrjZw5g0d1tp8New="
REDIS_PASSWORD="encrypted:BIgpV7btyiGYyySYnG3+NJVGUzNzB4zWjIZbM/VgtnPuiuSsK/KBkirtqkDBI8U/04BRKtupOTNSJTVu6GO39XPSpPvlxA4fNRyeK85W+rFGARp4mrgqfEz/O/eZvqJSqS5kNraAhbkKpXq81rEOBg=="

# API 配置
API_BASE_URL="encrypted:BMVEIPBGe9xkELFb48KQJPxxnTkUGhsonAU4ug5ca9E5eD/MZimkoQrf/3cb9nhazwfTbScLgeGGr/Jhj4DV7Xpz45XEEFWrPXy1Yi93zWLaJ4XYBHwCke3b4XCbh7jV4uL3WWFjI757yTIS6ilD"
JWT_SECRET="encrypted:BCrnJ2sAZH2qwRlPvUqqWyEsd+cVeMQiOV5H/xZ7vjFfcMXHMunmAv/7+jUI356fkVtHfrXu+vBJLjXJiirgB2gky5vvy7h5jevgMS6BgPL5KwjC0tYPlYbe4Bfrf1funYqqrFYaPjsEO+77vCtVaBPz"
JWT_EXPIRES_IN="encrypted:BKzfW56VHobMDtfq+iU+MsjVlPDdiKYoJmKLMlUKzsds5dHWjY+GcKbUx7V54jX21kVa6kuBcINNmP/DwXZA2VSb6q8zhMU/Go59aQWqmoqip6jB8DTxc8GjxUF4lWO3PLWJqk8="

# 第三方服务
STRIPE_PUBLISHABLE_KEY="encrypted:BOD5Fg+qI9dqhkh+gjCLrTFyhxEAhNDtLgwjkMZOr9l9CsvvhprwCrgsZbIRIFa1Vf6ATnWZ3/bacYnlBXlZ1Hc6YMZHog+ZuVW4AjwxCkB8I0AkcOeOsYzQx2fdtI4kFii01UIhN53jfmUjzLSPYw=="
STRIPE_SECRET_KEY="encrypted:BOD5Fg+qI9dqhkh+gjCLrTFyhxEAhNDtLgwjkMZOr9l9CsvvhprwCrgsZbIRIFa1Vf6ATnWZ3/bacYnlBXlZ1Hc6YMZHog+ZuVW4AjwxCkB8I0AkcOeOsYzQx2fdtI4kFii01UIhN53jfmUjzLSPYw=="
SENDGRID_API_KEY="encrypted:BCrnJ2sAZH2qwRlPvUqqWyEsd+cVeMQiOV5H/xZ7vjFfcMXHMunmAv/7+jUI356fkVtHfrXu+vBJLjXJiirgB2gky5vvy7h5jevgMS6BgPL5KwjC0tYPlYbe4Bfrf1funYqqrFYaPjsEO+77vCtVaBPz"

# 日志配置
LOG_LEVEL="encrypted:BKzfW56VHobMDtfq+iU+MsjVlPDdiKYoJmKLMlUKzsds5dHWjY+GcKbUx7V54jX21kVa6kuBcINNmP/DwXZA2VSb6q8zhMU/Go59aQWqmoqip6jB8DTxc8GjxUF4lWO3PLWJqk8="
LOG_FORMAT="encrypted:BKzfW56VHobMDtfq+iU+MsjVlPDdiKYoJmKLMlUKzsds5dHWjY+GcKbUx7V54jX21kVa6kuBcINNmP/DwXZA2VSb6q8zhMU/Go59aQWqmoqip6jB8DTxc8GjxUF4lWO3PLWJqk8="

# 功能开关
FEATURE_NEW_UI="encrypted:BKzfW56VHobMDtfq+iU+MsjVlPDdiKYoJmKLMlUKzsds5dHWjY+GcKbUx7V54jX21kVa6kuBcINNmP/DwXZA2VSb6q8zhMU/Go59aQWqmoqip6jB8DTxc8GjxUF4lWO3PLWJqk8="
FEATURE_ANALYTICS="encrypted:BKzfW56VHobMDtfq+iU+MsjVlPDdiKYoJmKLMlUKzsds5dHWjY+GcKbUx7V54jX21kVa6kuBcINNmP/DwXZA2VSb6q8zhMU/Go59aQWqmoqip6jB8DTxc8GjxUF4lWO3PLWJqk8="

.env.local (本地开发覆盖)

# 本地开发特定配置
DB_HOST=localhost
DB_NAME=myapp_local
DB_USER=localuser
DB_PASSWORD=localpass

# 本地调试
DEBUG=true
LOG_LEVEL=debug

# 本地服务端口
PORT=3001

# 禁用某些功能
FEATURE_ANALYTICS=false
FEATURE_EMAIL_NOTIFICATIONS=false

# 本地测试密钥
STRIPE_SECRET_KEY=sk_test_local_key
SENDGRID_API_KEY=SG.local_test_key

.env.test (测试环境)

# 测试环境配置
NODE_ENV=test
PORT=0

# 测试数据库
DB_HOST=localhost
DB_PORT=5433
DB_NAME=myapp_test
DB_USER=test_user
DB_PASSWORD=test_pass

# 测试 Redis
REDIS_HOST=localhost
REDIS_PORT=6380

# 测试 API
API_BASE_URL=http://localhost:3000/api
JWT_SECRET=test-secret-key
JWT_EXPIRES_IN=1h

# 禁用外部服务
STRIPE_SECRET_KEY=sk_test_fake
SENDGRID_API_KEY=SG.test_fake
EMAIL_ENABLED=false

# 测试日志
LOG_LEVEL=error
LOG_FORMAT=simple

# 测试功能开关
FEATURE_NEW_UI=true
FEATURE_ANALYTICS=false

.env.example (模板文件)

# 应用配置
NODE_ENV=development
PORT=3000
APP_NAME=MyApp
APP_VERSION=1.0.0

# 数据库配置
DB_HOST=localhost
DB_PORT=5432
DB_NAME=your_database_name
DB_USER=your_database_user
DB_PASSWORD=your_database_password

# Redis 配置
REDIS_HOST=localhost
REDIS_PORT=6379
REDIS_PASSWORD=your_redis_password

# API 配置
API_BASE_URL=http://localhost:3000/api
JWT_SECRET=your_jwt_secret_key
JWT_EXPIRES_IN=24h

# 第三方服务密钥
STRIPE_PUBLISHABLE_KEY=pk_test_your_stripe_publishable_key
STRIPE_SECRET_KEY=sk_test_your_stripe_secret_key
SENDGRID_API_KEY=SG.your_sendgrid_api_key

# 日志配置
LOG_LEVEL=info
LOG_FORMAT=combined

# 功能开关
FEATURE_NEW_UI=false
FEATURE_ANALYTICS=true

高级配置示例

变量扩展示例

# 基础配置
BASE_DOMAIN=example.com
PROTOCOL=https
PORT=443

# 扩展配置
API_URL=${PROTOCOL}://${BASE_DOMAIN}:${PORT}/api
WEB_URL=${PROTOCOL}://${BASE_DOMAIN}
WEBHOOK_URL=${API_URL}/webhooks

# 数据库连接字符串
DB_HOST=localhost
DB_PORT=5432
DB_NAME=myapp
DB_USER=admin
DB_PASS=secret123
DATABASE_URL=postgres://${DB_USER}:${DB_PASS}@${DB_HOST}:${DB_PORT}/${DB_NAME}

# 默认值
CACHE_TTL=${CACHE_TTL:-3600}
MAX_CONNECTIONS=${MAX_CONNECTIONS:-100}

命令替换示例

# Git 信息
COMMIT_SHA=$(git rev-parse HEAD)
BRANCH_NAME=$(git branch --show-current)
BUILD_TIME=$(date -u +"%Y-%m-%dT%H:%M:%SZ")

# 系统信息
HOSTNAME=$(hostname)
USER_NAME=$(whoami)

# 动态配置
CURRENT_VERSION=$(node -p "require('./package.json').version")
NODE_VERSION=$(node --version)

多服务配置示例

# 微服务配置
USER_SERVICE_URL=http://user-service:3001
ORDER_SERVICE_URL=http://order-service:3002
PAYMENT_SERVICE_URL=http://payment-service:3003
NOTIFICATION_SERVICE_URL=http://notification-service:3004

# 服务发现
CONSUL_HOST=consul
CONSUL_PORT=8500
SERVICE_REGISTRY_URL=http://${CONSUL_HOST}:${CONSUL_PORT}

# 负载均衡
NGINX_UPSTREAM_SERVERS=app1:3000,app2:3000,app3:3000

# 监控配置
PROMETHEUS_URL=http://prometheus:9090
GRAFANA_URL=http://grafana:3000
JAEGER_URL=http://jaeger:14268

部署脚本示例

package.json 脚本

{
  "scripts": {
    "dev": "dotenvx run -f .env.local -f .env -- npm run start:dev",
    "start": "dotenvx run -- node dist/main.js",
    "start:prod": "dotenvx run -f .env.production -- node dist/main.js",
    "test": "dotenvx run -f .env.test -- jest",
    "test:e2e": "dotenvx run -f .env.test -- jest --config ./test/jest-e2e.json",
    "build": "dotenvx run -- npm run build:app",
    "encrypt:prod": "dotenvx encrypt -f .env.production",
    "validate:env": "dotenvx validate -f .env.production"
  }
}

Docker Compose 示例

version: '3.8'
services:
  app:
    build: .
    command: dotenvx run -f .env.production -- node app.js
    environment:
      - DOTENV_PRIVATE_KEY_PRODUCTION=${DOTENV_PRIVATE_KEY_PRODUCTION}
    volumes:
      - ./.env.production:/app/.env.production:ro
    ports:
      - "3000:3000"
    depends_on:
      - db
      - redis

  db:
    image: postgres:15
    environment:
      - POSTGRES_DB=myapp
      - POSTGRES_USER=admin
      - POSTGRES_PASSWORD=secret123
    volumes:
      - postgres_data:/var/lib/postgresql/data

  redis:
    image: redis:7-alpine
    command: redis-server --requirepass secret123

volumes:
  postgres_data:

Kubernetes ConfigMap 示例

apiVersion: v1
kind: ConfigMap
metadata:
  name: app-env-config
data:
  .env.production: |
    DOTENV_PUBLIC_KEY_PRODUCTION="026d4945b6513baec60f68b207f203ba534fb54d2b0c9952557d240815e42a7d83"
    NODE_ENV="encrypted:BKzfW56VHobMDtfq+iU+MsjVlPDdiKYoJmKLMlUKzsds5dHWjY+GcKbUx7V54jX21kVa6kuBcINNmP/DwXZA2VSb6q8zhMU/Go59aQWqmoqip6jB8DTxc8GjxUF4lWO3PLWJqk8="
    # ... 其他加密变量
---
apiVersion: v1
kind: Secret
metadata:
  name: dotenv-private-key
type: Opaque
data:
  DOTENV_PRIVATE_KEY_PRODUCTION: YmQ3YzUwYjM1MmNlMjM5NzNlYzlkYjM1NWQ3MDIxMjMwNWEwYmFhYWRlOTJmMDE2NWYwMjkxNWIyMTNiZmJlMg==

TOML 配置集成示例

基础 TOML 配置结合 dotenvx

config.toml (应用配置)

[app]
name = "MyApp"
version = "1.0.0"
debug = false

[server]
host = "0.0.0.0"
port = 3000
timeout = 30

[database]
driver = "postgres"
max_connections = 100
ssl_mode = "require"

[redis]
pool_size = 10
timeout = 5

[logging]
format = "json"
rotation = "daily"

[features]
new_ui = true
analytics = false
rate_limiting = true

.env (敏感配置)

# 数据库连接
DB_HOST=localhost
DB_PORT=5432
DB_NAME=myapp
DB_USER=admin
DB_PASSWORD=secret123

# Redis 连接
REDIS_HOST=localhost
REDIS_PORT=6379
REDIS_PASSWORD=redis_secret

# API 密钥
JWT_SECRET=your_jwt_secret_key
STRIPE_SECRET_KEY=sk_test_your_stripe_key
SENDGRID_API_KEY=SG.your_sendgrid_key

# 外部服务
WEBHOOK_SECRET=webhook_secret_key
OAUTH_CLIENT_SECRET=oauth_client_secret

Node.js 集成示例

// config.js
const fs = require('fs')
const toml = require('toml')
require('@dotenvx/dotenvx').config()

// 读取 TOML 配置
const configFile = fs.readFileSync('./config.toml', 'utf8')
const config = toml.parse(configFile)

// 合并环境变量
const fullConfig = {
  ...config,
  database: {
    ...config.database,
    host: process.env.DB_HOST,
    port: parseInt(process.env.DB_PORT),
    name: process.env.DB_NAME,
    user: process.env.DB_USER,
    password: process.env.DB_PASSWORD,
    url: `postgres://${process.env.DB_USER}:${process.env.DB_PASSWORD}@${process.env.DB_HOST}:${process.env.DB_PORT}/${process.env.DB_NAME}`
  },
  redis: {
    ...config.redis,
    host: process.env.REDIS_HOST,
    port: parseInt(process.env.REDIS_PORT),
    password: process.env.REDIS_PASSWORD
  },
  auth: {
    jwtSecret: process.env.JWT_SECRET,
    jwtExpiresIn: '24h'
  },
  services: {
    stripe: {
      secretKey: process.env.STRIPE_SECRET_KEY
    },
    sendgrid: {
      apiKey: process.env.SENDGRID_API_KEY
    }
  }
}

module.exports = fullConfig

Rust 项目集成示例

Cargo.toml

[package]
name = "myapp"
version = "0.1.0"
edition = "2021"

[dependencies]
tokio = { version = "1.0", features = ["full"] }
serde = { version = "1.0", features = ["derive"] }
toml = "0.8"
dotenv = "0.15"
config = "0.14"

config.toml

[app]
name = "MyRustApp"
version = "0.1.0"
workers = 4

[server]
host = "127.0.0.1"
port = 8080
keep_alive = 75

[database]
pool_size = 10
timeout = 30
ssl = true

[cache]
ttl = 3600
max_size = "100MB"

src/config.rs

use serde::{Deserialize, Serialize};
use std::env;
use std::fs;

#[derive(Debug, Deserialize, Serialize)]
pub struct Config {
    pub app: AppConfig,
    pub server: ServerConfig,
    pub database: DatabaseConfig,
    pub cache: CacheConfig,
}

#[derive(Debug, Deserialize, Serialize)]
pub struct AppConfig {
    pub name: String,
    pub version: String,
    pub workers: u32,
}

#[derive(Debug, Deserialize, Serialize)]
pub struct ServerConfig {
    pub host: String,
    pub port: u16,
    pub keep_alive: u64,
}

#[derive(Debug, Deserialize, Serialize)]
pub struct DatabaseConfig {
    pub pool_size: u32,
    pub timeout: u64,
    pub ssl: bool,
    pub url: String,
}

#[derive(Debug, Deserialize, Serialize)]
pub struct CacheConfig {
    pub ttl: u64,
    pub max_size: String,
    pub redis_url: String,
}

impl Config {
    pub fn load() -> Result<Self, Box<dyn std::error::Error>> {
        // 加载 dotenv
        dotenv::dotenv().ok();

        // 读取 TOML 配置
        let config_str = fs::read_to_string("config.toml")?;
        let mut config: Config = toml::from_str(&config_str)?;

        // 从环境变量补充敏感信息
        config.database.url = format!(
            "postgres://{}:{}@{}:{}/{}",
            env::var("DB_USER")?,
            env::var("DB_PASSWORD")?,
            env::var("DB_HOST")?,
            env::var("DB_PORT")?,
            env::var("DB_NAME")?
        );

        config.cache.redis_url = format!(
            "redis://:{}@{}:{}",
            env::var("REDIS_PASSWORD").unwrap_or_default(),
            env::var("REDIS_HOST")?,
            env::var("REDIS_PORT")?
        );

        Ok(config)
    }
}

Python 项目集成示例

pyproject.toml

[tool.poetry]
name = "myapp"
version = "0.1.0"
description = "My Python App"

[tool.poetry.dependencies]
python = "^3.9"
fastapi = "^0.104.0"
uvicorn = "^0.24.0"
python-dotenv = "^1.0.0"
toml = "^0.10.2"
pydantic = "^2.5.0"
sqlalchemy = "^2.0.0"

[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"

[tool.app]
name = "MyPythonApp"
version = "0.1.0"
debug = false

[tool.app.server]
host = "0.0.0.0"
port = 8000
workers = 4

[tool.app.database]
pool_size = 20
echo = false
pool_timeout = 30

[tool.app.cache]
default_timeout = 300
key_prefix = "myapp:"

config.py

import os
import toml
from pathlib import Path
from pydantic import BaseSettings
from dotenv import load_dotenv

# 加载环境变量
load_dotenv()

class Settings(BaseSettings):
    # 从 TOML 加载基础配置
    def __init__(self):
        super().__init__()
        self._load_toml_config()

    def _load_toml_config(self):
        config_path = Path("pyproject.toml")
        if config_path.exists():
            with open(config_path, 'r') as f:
                toml_config = toml.load(f)
                app_config = toml_config.get('tool', {}).get('app', {})

                # 合并 TOML 配置
                self.app_name = app_config.get('name', 'MyApp')
                self.app_version = app_config.get('version', '0.1.0')
                self.debug = app_config.get('debug', False)

                server_config = app_config.get('server', {})
                self.host = server_config.get('host', '0.0.0.0')
                self.port = server_config.get('port', 8000)
                self.workers = server_config.get('workers', 4)

    # 敏感配置从环境变量获取
    database_url: str = os.getenv('DATABASE_URL', '')
    redis_url: str = os.getenv('REDIS_URL', '')
    secret_key: str = os.getenv('SECRET_KEY', '')

    # API 密钥
    stripe_secret_key: str = os.getenv('STRIPE_SECRET_KEY', '')
    sendgrid_api_key: str = os.getenv('SENDGRID_API_KEY', '')

    class Config:
        env_file = '.env'
        case_sensitive = True

settings = Settings()

Go 项目集成示例

config.toml

[app]
name = "MyGoApp"
version = "1.0.0"
environment = "development"

[server]
host = "localhost"
port = 8080
read_timeout = "30s"
write_timeout = "30s"
idle_timeout = "60s"

[database]
max_open_conns = 25
max_idle_conns = 5
conn_max_lifetime = "5m"

[cache]
default_expiration = "10m"
cleanup_interval = "15m"

config.go

package config

import (
    "fmt"
    "os"
    "time"

    "github.com/BurntSushi/toml"
    "github.com/joho/godotenv"
)

type Config struct {
    App      AppConfig      `toml:"app"`
    Server   ServerConfig   `toml:"server"`
    Database DatabaseConfig `toml:"database"`
    Cache    CacheConfig    `toml:"cache"`

    // 敏感信息从环境变量获取
    DatabaseURL    string
    RedisURL       string
    JWTSecret      string
    StripeKey      string
    SendGridKey    string
}

type AppConfig struct {
    Name        string `toml:"name"`
    Version     string `toml:"version"`
    Environment string `toml:"environment"`
}

type ServerConfig struct {
    Host         string        `toml:"host"`
    Port         int           `toml:"port"`
    ReadTimeout  time.Duration `toml:"read_timeout"`
    WriteTimeout time.Duration `toml:"write_timeout"`
    IdleTimeout  time.Duration `toml:"idle_timeout"`
}

type DatabaseConfig struct {
    MaxOpenConns    int           `toml:"max_open_conns"`
    MaxIdleConns    int           `toml:"max_idle_conns"`
    ConnMaxLifetime time.Duration `toml:"conn_max_lifetime"`
}

type CacheConfig struct {
    DefaultExpiration time.Duration `toml:"default_expiration"`
    CleanupInterval   time.Duration `toml:"cleanup_interval"`
}

func Load() (*Config, error) {
    // 加载 .env 文件
    if err := godotenv.Load(); err != nil {
        // .env 文件不存在时不报错
        fmt.Println("Warning: .env file not found")
    }

    var config Config

    // 读取 TOML 配置
    if _, err := toml.DecodeFile("config.toml", &config); err != nil {
        return nil, fmt.Errorf("failed to decode config.toml: %w", err)
    }

    // 从环境变量获取敏感信息
    config.DatabaseURL = fmt.Sprintf(
        "postgres://%s:%s@%s:%s/%s?sslmode=require",
        os.Getenv("DB_USER"),
        os.Getenv("DB_PASSWORD"),
        os.Getenv("DB_HOST"),
        os.Getenv("DB_PORT"),
        os.Getenv("DB_NAME"),
    )

    config.RedisURL = fmt.Sprintf(
        "redis://:%s@%s:%s",
        os.Getenv("REDIS_PASSWORD"),
        os.Getenv("REDIS_HOST"),
        os.Getenv("REDIS_PORT"),
    )

    config.JWTSecret = os.Getenv("JWT_SECRET")
    config.StripeKey = os.Getenv("STRIPE_SECRET_KEY")
    config.SendGridKey = os.Getenv("SENDGRID_API_KEY")

    return &config, nil
}

Docker 多阶段构建示例

Dockerfile

# 构建阶段
FROM node:18-alpine AS builder

WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production

# 复制配置文件
COPY config.toml ./
COPY .env.production ./

# 安装 dotenvx
RUN npm install -g @dotenvx/dotenvx

# 运行阶段
FROM node:18-alpine AS runner

WORKDIR /app

# 复制依赖和配置
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/config.toml ./
COPY --from=builder /app/.env.production ./
COPY --from=builder /usr/local/bin/dotenvx /usr/local/bin/

# 复制应用代码
COPY . .

# 使用 dotenvx 运行应用
CMD ["dotenvx", "run", "-f", ".env.production", "--", "node", "app.js"]

最佳实践总结

1. 配置分离原则

config.toml     -> 非敏感的应用配置
.env           -> 敏感信息(密码、密钥等)
.env.example   -> 环境变量模板

2. 环境特定配置

config.toml           -> 基础配置
config.dev.toml       -> 开发环境覆盖
config.prod.toml      -> 生产环境覆盖
.env.development      -> 开发环境敏感信息
.env.production       -> 生产环境敏感信息(加密)

3. 配置验证

// config-validator.js
const Joi = require('joi')

const configSchema = Joi.object({
  database: Joi.object({
    url: Joi.string().uri().required(),
    pool_size: Joi.number().min(1).max(100).required()
  }).required(),

  redis: Joi.object({
    url: Joi.string().uri().required(),
    timeout: Joi.number().min(1).required()
  }).required(),

  auth: Joi.object({
    jwtSecret: Joi.string().min(32).required()
  }).required()
})

function validateConfig(config) {
  const { error, value } = configSchema.validate(config)
  if (error) {
    throw new Error(`Configuration validation failed: ${error.message}`)
  }
  return value
}

module.exports = { validateConfig }

这些配置示例展示了 dotenvx 在不同环境和场景下的实际应用,特别是与 TOML 配置文件的结合使用,帮助开发者快速上手并在项目中正确使用 dotenvx。