Configuración y Ajustes
La configuración se carga desde el entorno al inicio, se valida una vez con Pydantic 2, y mantiene los secretos fuera del control de código fuente para que el mismo artefacto se ejecute en desarrollo, staging y producción.
Receta
Tarjeta de referencia rápida - lista para copiar y pegar.
from pydantic import Field
from pydantic_settings import BaseSettings, SettingsConfigDict
class Settings(BaseSettings):
model_config = SettingsConfigDict(env_file=".env", extra="ignore")
app_name: str = "billing-api"
database_url: str = Field(alias="DATABASE_URL")
debug: bool = False
settings = Settings()Cuándo usar esto:
- Al desplegar la misma imagen de contenedor en diferentes entornos.
- Para evitar que "funciona localmente" omita variables de entorno requeridas.
- Para centralizar tiempos de espera, flags de funcionalidades y URLs de servicios.
- Para auditar qué configuraciones existen sin leer llamadas dispersas a
os.getenv.
Ejemplo de Trabajo
# settings.py
from functools import lru_cache
from typing import Literal
from pydantic import Field, PostgresDsn, field_validator
from pydantic_settings import BaseSettings, SettingsConfigDict
class Settings(BaseSettings):
model_config = SettingsConfigDict(
env_file=".env",
env_file_encoding="utf-8",
extra="ignore",
)
environment: Literal["local", "staging", "production"] = "local"
app_name: str = "orders-api"
log_level: Literal["DEBUG", "INFO", "WARNING", "ERROR"] = "INFO"
database_url: PostgresDsn
redis_url: str = "redis://localhost:6379/0"
secret_key: str = Field(min_length=32)
http_timeout_seconds: float = 5.0
@field_validator("secret_key")
@classmethod
def forbid_placeholder_secret(cls, value: str) -> str:
if value in {"changeme", "replace-me"}:
raise ValueError("SECRET_KEY debe configurarse con un valor real")
return value
@lru_cache
def get_settings() -> Settings:
return Settings()
# main wiring
import logging
def configure_logging(settings: Settings) -> None:
logging.basicConfig(level=settings.log_level)
def build_app():
settings = get_settings()
configure_logging(settings)
# pasar settings.database_url a la fábrica del repositorio
return settings
if __name__ == "__main__":
s = build_app()
print(f"{s.app_name} listo en {s.environment}")# .env.example (en el repositorio - sin secretos)
DATABASE_URL=postgresql://user:pass@localhost:5432/orders
SECRET_KEY=generate-a-32-char-random-string-for-local-dev
ENVIRONMENT=local
LOG_LEVEL=DEBUGLo que esto demuestra:
- Los secretos requeridos fallan rápidamente al importar/iniciar con errores de validación claros.
.envsoporta el desarrollo local; la producción depende de variables de entorno reales.get_settings()se cachea para que el análisis ocurra una vez por proceso.extra="ignore"evita que los errores tipográficos creen atributos silenciosamente.
Inmersión Profunda
Cómo Funciona
- Pydantic Settings lee las variables de entorno (y el opcional
.env) en campos tipados. - Los alias de campo mapean el nombre de la variable de entorno
DATABASE_URLal atributodatabase_url. - Los validadores imponen reglas de negocio más allá de la coerción de tipos.
- La raíz de composición llama a
get_settings()y pasa los valores a los adaptadores.
Lista de Verificación 12-Factor
| Factor | Práctica en Python |
|---|---|
| Configuración en el entorno | BaseSettings, no URLs de producción codificadas |
| Paridad desarrollo/producción | misma clase de configuración, diferentes valores de entorno |
| Secretos | almacén de secretos de la plataforma → entorno en tiempo de ejecución |
| Servicios de respaldo | URLs como configuraciones, intercambiables por entorno |
Notas de Python
# Configuración anidada para subsistemas
from pydantic_settings import BaseSettings
class S3Settings(BaseSettings):
model_config = SettingsConfigDict(env_prefix="S3_")
bucket: str
region: str = "us-east-1"
class Settings(BaseSettings):
s3: S3Settings = S3Settings()Errores Comunes
- Confirmar
.envcon secretos - las claves se filtran a través del historial de git. Solución: confirmar solo.env.example; bloquear.enven.gitignore. - Leer variables de entorno en el momento de la importación en todas partes - módulos no testeables y dependencias de orden ocultas. Solución: un módulo de configuración; inyectar en las fábricas.
- Sin validación en URLs - un DSN incorrecto falla profundamente en SQLAlchemy. Solución:
PostgresDsn,RedisDsn, o validadores personalizados al inicio. - Sorpresas con variables booleanas de entorno - la cadena
"false"es verdadera en unif os.getenv("X")ingenuo. Solución: el análisisboolde Pydantic maneja0,false,no. - Singleton de configuración mutable - el código muta
settings.debug = Trueen tiempo de ejecución. Solución: tratar la configuración como inmutable después de la carga; usar modelosfrozen=Truecuando sea práctico. - Mezclar configuración de Django con pydantic-settings - dos fuentes de verdad. Solución: elegir un patrón por aplicación; conectar solo en la raíz de composición.
Alternativas
| Alternativa | Usar Cuando | No Usar Cuando |
|---|---|---|
os.environ directamente | scripts de 10 líneas | servicios con docenas de configuraciones |
Django settings.py | proyectos Django 5.2 | servicios FastAPI/Flask independientes |
| Archivos de configuración TOML/YAML | valores predeterminados estáticos no secretos | secretos que no deben residir en disco |
python-decouple | proyectos heredados que ya lo usan | pilas Pydantic nuevas |
Preguntas Frecuentes
¿Debo usar .env en producción?
La producción debe inyectar variables de entorno a través del orquestador o gestor de secretos. Los archivos .env en los servidores son un vector de fuga común. El desarrollo local puede usar .env cómodamente.
¿Cómo nombro las variables de entorno?
Usa SCREAMING_SNAKE_CASE. Prefiere alias de campo cuando el nombre externo difiere del atributo de Python (DATABASE_URL → database_url).
¿Cómo pruebo código que necesita configuración?
Usa monkeypatch.setenv antes de llamar a get_settings.cache_clear() y reinstanciar, o pasa un objeto Settings construido manualmente a las fábricas.
¿Puede la configuración cargarse desde AWS Secrets Manager?
Sí: recupera los secretos en la raíz de composición y pásalos como variables de entorno antes de construir Settings, o usa una fuente de configuración personalizada (fuentes personalizadas de Pydantic v2).
¿Dónde van los flags de funcionalidades?
Trata los flags como campos de configuración (FEATURE_NEW_CHECKOUT: bool = False). Documenta los valores predeterminados en .env.example.
¿Cómo manejo múltiples entornos en CI?
CI establece las variables de entorno explícitamente en el archivo de flujo de trabajo. No confíes en un .env confirmado para los secretos de la canalización.
¿Deben las configuraciones anidadas usar env_prefix?
Sí, para grupos como S3_BUCKET, S3_REGION. Mantiene las variables de entorno planas organizadas sin una única clase plana gigante.
¿Cómo funciona esto con Docker?
Pasa -e o env_file en compose para los no secretos. Monta secretos desde la plataforma (secretos de Kubernetes, secretos de ECS) como variables de entorno al inicio del contenedor.
¿Qué pasa con los secretos predeterminados en el código?
Nunca para rutas de producción. Los valores predeterminados solo para desarrollo pertenecen a .env.example con valores de marcador de posición obvios rechazados por los validadores.
¿Puedo usar pydantic-settings con FastAPI?
Sí. Depends(get_settings) proporciona la configuración a las rutas y fábricas de dependencias sin importaciones globales.
¿Cómo versiono cambios de configuración que rompen la compatibilidad?
Documenta los cambios de nombre en CHANGELOG y soporta nombres de variables de entorno obsoletos durante un lanzamiento con una advertencia del validador.
¿Son aceptables las configuraciones calculadas?
Usa @computed_field para valores derivados (por ejemplo, modo debug cuando environment == "local"). Mantén las entradas en el entorno, las derivaciones en el código.
Relacionado
- Inyección de Dependencias y Conexión - inyectar configuración en la raíz
- Lista de Verificación de Decisiones de Arquitectura de Proyecto - decisiones de configuración por adelantado
- Lista de Verificación de Auditoría de Código Fuente - señales de alerta de secretos y configuración
- Conflictos de Dependencias y Entorno - depuración de desajustes de entorno
- Mejores Prácticas de Arquitectura - hábitos de configuración
Versiones de Stack: Esta página fue escrita para Python 3.14.0 (estable 3.14, mantenimiento 3.13), FastAPI 0.115+, Django 5.2, Flask 3.1, Pydantic 2, PyTorch 2.6+, pandas 2.2+, Polars 1.x, ruff 0.9+, y uv 0.6+.