Configuración con pydantic-settings

Intermedio
FastAPI
FastAPI
Actualizado: 18/04/2026

Diagrama: Fastapi configuracion settings

¿Por qué gestionar la configuración con pydantic-settings?

La configuración de una aplicación incluye todo lo que puede variar entre entornos: URLs de base de datos, claves secretas, nombres de buckets de almacenamiento, credenciales de servicios externos, flags de funcionalidades, etc.

La mejor práctica (uno de los principios de la metodología 12-Factor App) es almacenar la configuración en variables de entorno, separándola completamente del código fuente. Esto permite que el mismo código funcione en desarrollo, staging y producción sin modificaciones.

pydantic-settings lleva esta práctica un paso más allá: define la configuración como un modelo Pydantic tipado que:

  • Carga los valores desde variables de entorno o archivos .env
  • Válida los tipos automáticamente (una URL incorrecta falla en el arranque)
  • Lanza errores claros si falta una variable obligatoria
  • Soporta valores por defecto para desarrollo

Instalación

pip install pydantic-settings

pydantic-settings es un paquete separado de Pydantic desde la versión 2.

Definir el modelo de configuración

# app/config.py
from pydantic_settings import BaseSettings, SettingsConfigDict
from pydantic import AnyHttpUrl, field_validator
from typing import Annotated

class Configuracion(BaseSettings):
    model_config = SettingsConfigDict(
        env_file=".env",           # Cargar desde .env si existe
        env_file_encoding="utf-8",
        case_sensitive=False,      # DATABASE_URL y database_url son lo mismo
    )

    # Nombre de la aplicación
    app_name: str = "Mi API FastAPI"
    app_version: str = "1.0.0"

    # Base de datos (obligatoria, sin valor por defecto)
    database_url: str

    # Seguridad (obligatoria en producción)
    secret_key: str
    algorithm: str = "HS256"
    access_token_expire_minutes: int = 30

    # Entorno de ejecución
    environment: str = "desarrollo"
    debug: bool = False

    # Configuración del servidor
    host: str = "0.0.0.0"
    port: int = 8000

    # CORS
    allowed_origins: list[str] = ["http://localhost:3000"]

    @field_validator("environment")
    @classmethod
    def validar_entorno(cls, v: str) -> str:
        entornos_validos = {"desarrollo", "staging", "produccion"}
        if v not in entornos_validos:
            raise ValueError(f"El entorno debe ser uno de: {entornos_validos}")
        return v

Archivo .env

El archivo .env almacena los valores de configuración para el entorno local:

# .env (no incluir en el repositorio Git)
DATABASE_URL=postgresql://usuario:contrasena@localhost/mi_bd
SECRET_KEY=mi-clave-secreta-muy-segura-y-larga-123456789
ENVIRONMENT=desarrollo
DEBUG=true
ALLOWED_ORIGINS=["http://localhost:3000","http://localhost:5173"]

Añade .env al archivo .gitignore para no incluirlo accidentalmente en el repositorio:

echo ".env" >> .gitignore

Para el repositorio, puedes incluir un .env.example con las variables necesarias pero sin valores reales:

# .env.example (sí se incluye en el repositorio)
DATABASE_URL=postgresql://usuario:contrasena@localhost/mi_bd
SECRET_KEY=cambia-esto-por-una-clave-secreta-real
ENVIRONMENT=desarrollo
DEBUG=false
ALLOWED_ORIGINS=["http://localhost:3000"]

Usar la configuración en FastAPI

La forma recomendada de integrar la configuración en FastAPI es mediante una dependencia con caché:

# app/config.py (ampliado)
from functools import lru_cache

@lru_cache
def get_settings() -> Configuracion:
    """Carga la configuración una sola vez y la cachea."""
    return Configuracion()
# app/main.py
from fastapi import FastAPI, Depends
from app.config import Configuracion, get_settings

def create_app(settings: Configuracion) -> FastAPI:
    """Factory de la aplicación que recibe la configuración."""
    app = FastAPI(
        title=settings.app_name,
        version=settings.app_version,
        debug=settings.debug,
    )

    # Configurar CORS con los orígenes de la configuración
    from fastapi.middleware.cors import CORSMiddleware
    app.add_middleware(
        CORSMiddleware,
        allow_origins=settings.allowed_origins,
        allow_credentials=True,
        allow_methods=["*"],
        allow_headers=["*"],
    )

    return app

settings = get_settings()
app = create_app(settings)

# Endpoint que expone información de configuración pública
@app.get("/info")
async def info_aplicacion(config: Configuracion = Depends(get_settings)):
    return {
        "nombre": config.app_name,
        "version": config.app_version,
        "entorno": config.environment,
    }

El uso de @lru_cache garantiza que el archivo .env se lee y válida una sola vez al arrancar la aplicación. Las llamadas posteriores a get_settings() devuelven la misma instancia cacheada.

Configuraciones específicas por entorno

Para entornos distintos, puedes heredar de la configuración base:

# app/config.py
from pydantic_settings import BaseSettings, SettingsConfigDict

class ConfiguracionBase(BaseSettings):
    app_name: str = "Mi API"
    database_url: str
    secret_key: str
    debug: bool = False
    allowed_origins: list[str] = []

class ConfiguracionDesarrollo(ConfiguracionBase):
    model_config = SettingsConfigDict(env_file=".env.development")

    debug: bool = True
    database_url: str = "sqlite:///./desarrollo.db"
    secret_key: str = "dev-secret-key-no-usar-en-produccion"
    allowed_origins: list[str] = [
        "http://localhost:3000",
        "http://localhost:5173",
    ]

class ConfiguracionProduccion(ConfiguracionBase):
    model_config = SettingsConfigDict(env_file=".env.production")

    debug: bool = False
    # Estos valores DEBEN venir de variables de entorno reales

import os
from functools import lru_cache

@lru_cache
def get_settings():
    entorno = os.getenv("ENVIRONMENT", "desarrollo")
    if entorno == "produccion":
        return ConfiguracionProduccion()
    return ConfiguracionDesarrollo()

Inyectar configuración en endpoints

La configuración se puede inyectar como una dependencia normal en cualquier endpoint:

from fastapi import FastAPI, Depends
from app.config import Configuracion, get_settings

app = FastAPI()

@app.get("/estado")
async def estado_sistema(config: Configuracion = Depends(get_settings)):
    return {
        "app": config.app_name,
        "version": config.app_version,
        "entorno": config.environment,
        "debug": config.debug,
    }

@app.get("/feature-flags")
async def obtener_flags(config: Configuracion = Depends(get_settings)):
    # Algunos flags pueden estar en la configuración
    return {
        "modo_mantenimiento": getattr(config, "modo_mantenimiento", False),
        "registro_habilitado": True,
    }

Testing con configuración sobreescrita

Para los tests, sobreescribe la dependencia get_settings con una configuración de test:

# tests/conftest.py
import pytest
from fastapi.testclient import TestClient
from app.main import app
from app.config import Configuracion, get_settings

class ConfiguracionTest(Configuracion):
    database_url: str = "sqlite://"
    secret_key: str = "test-secret-key-123"
    environment: str = "desarrollo"
    debug: bool = True

@pytest.fixture
def client():
    config_test = ConfiguracionTest()
    app.dependency_overrides[get_settings] = lambda: config_test

    with TestClient(app) as test_client:
        yield test_client

    app.dependency_overrides.clear()

Este patrón garantiza que los tests usan siempre una configuración predecible y no dependen de variables de entorno del sistema del desarrollador.

Fuentes y referencias

Documentación oficial y recursos externos para profundizar en FastAPI

Documentación oficial de FastAPI
Alan Sastre - Autor del tutorial

Alan Sastre

Ingeniero de Software y formador, CEO en CertiDevs

Ingeniero de software especializado en Full Stack y en Inteligencia Artificial. Como CEO de CertiDevs, FastAPI es una de sus áreas de expertise. Con más de 15 años programando, 6K seguidores en LinkedIn y experiencia como formador, Alan se dedica a crear contenido educativo de calidad para desarrolladores de todos los niveles.

Más tutoriales de FastAPI

Explora más contenido relacionado con FastAPI y continúa aprendiendo con nuestros tutoriales gratuitos.

Aprendizajes de esta lección

Instalar y configurar pydantic-settings para gestionar la configuración de la aplicación. Definir modelos de configuración con tipos y valores por defecto seguros. Cargar configuración desde variables de entorno y archivos .env. Inyectar la configuración como dependencia en los endpoints de FastAPI. Usar configuraciones específicas por entorno (desarrollo, staging, producción).