pydantic-settings
pydantic-settings extiende los modelos Pydantic para cargar configuración desde variables de entorno, archivos .env y directorios de secretos opcionales, con validación, conversión de tipos y mensajes de error claros al arrancar.
Receta
from pydantic import Field
from pydantic_settings import BaseSettings, SettingsConfigDict
class Settings(BaseSettings):
model_config = SettingsConfigDict(env_file=".env", extra="ignore")
database_url: str = Field(alias="DATABASE_URL")
debug: bool = False
api_key: str
settings = Settings() # lanza ValidationError si api_key faltaCuándo usar esto:
- Aplicaciones FastAPI/Django/Flask que leen
os.environ - Workers y CLIs que necesitan configuración tipada y documentada
- Reemplazo de conversiones manuales de
os.getenv("PORT", "8000") - Validación de configuración antes de que los workers de Gunicorn bifurcados arranquen
Ejemplo de Trabajo
from __future__ import annotations
from functools import lru_cache
from pydantic import Field, PostgresDsn
from pydantic_settings import BaseSettings, SettingsConfigDict
class Settings(BaseSettings):
model_config = SettingsConfigDict(
env_file=".env",
env_file_encoding="utf-8",
extra="ignore",
)
app_name: str = "billing-api"
database_url: PostgresDsn = Field(alias="DATABASE_URL")
redis_url: str = Field(default="redis://localhost:6379/0", alias="REDIS_URL")
log_level: str = "INFO"
@lru_cache
def get_settings() -> Settings:
return Settings()
def main() -> None:
s = get_settings()
print(s.app_name, s.database_url, s.log_level)
if __name__ == "__main__":
main()Lo que esto demuestra:
SettingsConfigDictcentraliza el archivo env y la política de ignorar claves desconocidasField(alias=...)mapea nombres en mayúsculas a atributos en snake_casePostgresDsnvalida la forma de la cadena de conexión tempranamente@lru_cacheproporciona configuración singleton al estilo FastAPI sin variables globales
Análisis Profundo
Cómo Funciona
- Prioridad de origen - Valores por defecto < archivo env < entorno real (el entorno tiene prioridad sobre el archivo).
- Conversión de tipos -
"true"se convierte enTruepara campos booleanos; las cadenas separadas por comas pueden convertirse en listas con analizadores personalizados. - Configuración anidada -
env_nested_delimiter="__"mapeaDB__HOSTadb.host. - Secretos -
secrets_dircarga archivos de secretos montados por Docker/Kubernetes como valores de campo.
Campos Comunes
| Tipo de Campo | Ejemplo de Env | Notas |
|---|---|---|
str | API_KEY=abc | Requerido si no hay valor por defecto |
bool | DEBUG=true | Acepta true/false/1/0 |
int | PORT=8000 | Valores inválidos lanzan error al arrancar |
list[str] | ORIGINS=a,b | Usa NoDecode + validador personalizado para CSV |
SecretStr | TOKEN=... | Oculta el valor en repr/logs |
Notas de Python
from pydantic import SecretStr
class Settings(BaseSettings):
token: SecretStr
# SecretStr se oculta en los logs
print(settings.token.get_secret_value()) # revelación explícitaTrampas Comunes
- Efectos secundarios en tiempo de importación -
settings = Settings()a nivel de módulo falla en las pruebas. Solución: factory +lru_cacheo inyección de dependencias. extra="allow"en producción - Errores tipográficos en nombres de env crean atributos silenciosamente. Solución:extra="ignore"o"forbid".- Confirmar
.envcon secretos - El historial de Git filtra credenciales. Solución: solo.env.example; cargar valores reales desde secretos de la plataforma. - Un solo Settings para monorepo - Acopla servicios no relacionados. Solución:
ApiSettings,WorkerSettingspor componente desplegable. - Falta de env en Docker - Una cadena vacía puede convertirse inesperadamente para enteros opcionales. Solución: usar
Optional[int] = Noney validar. - Sensibilidad a mayúsculas/minúsculas - Las claves de env son sensibles a mayúsculas/minúsculas en Linux. Solución: documentar los nombres exactos en
.env.example.
Alternativas
| Alternativa | Usar Cuando | No Usar Cuando |
|---|---|---|
os.environ + conversiones manuales | Scripts pequeños con 2-3 variables | Más de un puñado de configuraciones |
python-decouple | Proyectos Django heredados que ya lo usan | Pilas nuevas con Pydantic/FastAPI |
dynaconf | Capas YAML/TOML para múltiples entornos | Quieres tipos Pydantic de extremo a extremo |
django-environ | Configuración solo para Django | FastAPI o workers independientes |
Preguntas Frecuentes
¿Cómo pruebo con diferentes valores de env?
Limpia la caché y pasa el env mediante monkeypatch.setenv antes de llamar a get_settings() - o usa las anulaciones del constructor Settings(_env_file=None, api_key="test").
¿Puedo cargar múltiples archivos env?
Pasa env_file=(".env", ".env.local") - los archivos posteriores no anulan los anteriores a menos que las variables de entorno reales prevalezcan.
¿Cómo funcionan las configuraciones anidadas?
Define un campo BaseModel anidado y establece env_nested_delimiter="__" para que CACHE__TTL=300 se mapee correctamente.
¿Funciona esto con FastAPI Depends?
Sí - def settings_dep() -> Settings: return get_settings() e inyéctalo en las rutas.
¿Cómo valido indicadores mutuamente excluyentes?
Usa @model_validator(mode="after") para lanzar un error si se establecen tanto USE_SQLITE como DATABASE_URL.
¿Qué pasa con la vinculación de puertos 12-factor?
port: int = Field(default=8000, alias="PORT") - Heroku/Fly/Railway inyectan PORT automáticamente.
¿Puedo usar TOML en lugar de env?
pydantic-settings se enfoca en env; para aplicaciones con mucho TOML, combínalo con cargadores de secciones pyproject.toml o dynaconf.
¿Cómo documento la configuración para los operadores?
Genera un esquema JSON a partir del modelo o mantén un .env.example con cada clave y un valor de ejemplo.
¿SecretStr vs str simple?
Usa SecretStr para tokens y contraseñas para que el registro accidental no imprima secretos.
¿pydantic-settings funciona con Django?
Sí, en scripts independientes y workers ASGI; los proyectos de Django a menudo usan django-environ, pero la configuración de Pydantic funciona para los workers de Celery que comparten el mismo env.
Relacionado
- Conceptos Básicos de Pydantic - modelos y validación
- Configuración y Ajustes - patrones de arquitectura
- Conceptos Básicos de FastAPI - inyección de dependencias
- Gestión de Secretos - manejo de secretos en producció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+.