Configuração e Configurações
A configuração é carregada do ambiente na inicialização, validada uma vez com Pydantic 2 e mantém os segredos fora do controle de versão para que o mesmo artefato seja executado em desenvolvimento, staging e produção.
Receita
Cartão de receita de referência rápida - pronto para copiar e colar.
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()Quando usar isso:
- Ao implantar a mesma imagem de contêiner entre ambientes
- Para evitar que "funciona localmente" perca variáveis de ambiente necessárias
- Para centralizar timeouts, flags de recursos e URLs de serviço
- Para auditar quais configurações existem sem ler chamadas
os.getenvdispersas
Exemplo de Trabalho
# 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 must be set to a real value")
return value
@lru_cache
def get_settings() -> Settings:
return Settings()
# Conexão principal
import logging
def configure_logging(settings: Settings) -> None:
logging.basicConfig(level=settings.log_level)
def build_app():
settings = get_settings()
configure_logging(settings)
# passe settings.database_url para o factory do repositório
return settings
if __name__ == "__main__":
s = build_app()
print(f"{s.app_name} pronto em {s.environment}")# .env.example (commitado - sem segredos)
DATABASE_URL=postgresql://user:pass@localhost:5432/orders
SECRET_KEY=generate-a-32-char-random-string-for-local-dev
ENVIRONMENT=local
LOG_LEVEL=DEBUGO que isso demonstra:
- Segredos obrigatórios falham rapidamente na importação/inicialização com erros de validação claros
.envsuporta desenvolvimento local; produção depende de variáveis de ambiente reaisget_settings()cacheado para que a análise ocorra uma vez por processoextra="ignore"evita que erros de digitação criem atributos silenciosamente
Mergulho Profundo
Como Funciona
- Pydantic Settings lê variáveis de ambiente (e
.envopcional) em campos tipados - Aliases de campo mapeiam o nome da variável de ambiente
DATABASE_URLpara o atributodatabase_url - Validadores impõem regras de negócios além da coerção de tipo
- A raiz de composição chama
get_settings()e passa valores para os adaptadores
Checklist 12-Factor
| Fator | Prática Python |
|---|---|
| Configuração no ambiente | BaseSettings, não URLs de produção codificadas |
| Paridade dev/prod | mesma classe de configurações, valores de ambiente diferentes |
| Segredos | armazenamento de segredos da plataforma → ambiente em tempo de execução |
| Serviços de apoio | URLs como configurações, substituíveis por ambiente |
Notas Python
# Configurações aninhadas 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()Armadilhas
- Commitar
.envcom segredos - chaves vazam pelo histórico do git. Correção: comitar apenas.env.example; bloquear.envem.gitignore. - Ler variáveis de ambiente no tempo de importação em todos os lugares - módulos não testáveis e dependências de ordem ocultas. Correção: um módulo de configurações; injetar em factories.
- Sem validação em URLs - DSNs ruins falham profundamente no SQLAlchemy. Correção:
PostgresDsn,RedisDsn, ou validadores personalizados na inicialização. - Surpresas com variáveis de ambiente booleanas - a string
"false"é verdadeira emif os.getenv("X")ingênuo. Correção: o parsingbooldo Pydantic lida com0,false,no. - Singleton de configurações mutáveis - o código modifica
settings.debug = Trueem tempo de execução. Correção: tratar configurações como imutáveis após o carregamento; usar modelosfrozen=Truequando prático. - Misturar configurações Django com pydantic-settings - duas fontes de verdade. Correção: escolher um padrão por aplicativo; conectar apenas na raiz de composição.
Alternativas
| Alternativa | Usar Quando | Não Usar Quando |
|---|---|---|
os.environ diretamente | scripts de 10 linhas | serviços com dezenas de configurações |
Django settings.py | projetos Django 5.2 | serviços FastAPI/Flask independentes |
| Arquivos de configuração TOML/YAML | padrões estáticos não secretos | segredos que não devem residir no disco |
python-decouple | projetos legados que já o utilizam | pilhas Pydantic novas |
FAQs
Devo usar .env em produção?
A produção deve injetar variáveis de ambiente através do orquestrador ou gerenciador de segredos. Arquivos .env em servidores são um vetor de vazamento comum. O desenvolvimento local pode usar .env confortavelmente.
Como nomeio variáveis de ambiente?
Use SCREAMING_SNAKE_CASE. Prefira aliases de campo quando o nome externo diferir do atributo Python (DATABASE_URL → database_url).
Como testo código que precisa de configurações?
Use monkeypatch.setenv antes de chamar get_settings.cache_clear() e reinstanciar, ou passe um objeto Settings construído manualmente para os factories.
As configurações podem ser carregadas do AWS Secrets Manager?
Sim - busque segredos na raiz de composição e passe-os como variáveis de ambiente antes de construir Settings, ou use uma fonte de configurações personalizada (fontes personalizadas do Pydantic v2).
Onde vão as flags de recursos?
Trate as flags como campos de configuração (FEATURE_NEW_CHECKOUT: bool = False). Documente os padrões em .env.example.
Como lidar com múltiplos ambientes em CI?
CI define variáveis de ambiente explicitamente no arquivo de workflow. Não confie em um .env commitado para segredos de pipeline.
Configurações aninhadas devem usar env_prefix?
Sim para grupos como S3_BUCKET, S3_REGION. Mantém as variáveis de ambiente planas organizadas sem uma única classe plana gigante.
Como isso funciona com Docker?
Passe -e ou env_file no compose para não-segredos. Monte segredos da plataforma (segredos do Kubernetes, segredos do ECS) como variáveis de ambiente no início do contêiner.
E quanto a segredos padrão no código?
Nunca para caminhos de produção. Padrões apenas para desenvolvimento local pertencem a .env.example com valores de placeholder óbvios rejeitados por validadores.
Posso usar pydantic-settings com FastAPI?
Sim. Depends(get_settings) fornece configurações para rotas e factories de dependência sem importações globais.
Como versionar alterações de configuração que quebram compatibilidade?
Documente renomeações no CHANGELOG e suporte nomes de ambiente depreciados por uma versão com um aviso do validador.
Configurações computadas são aceitáveis?
Use @computed_field para valores derivados (por exemplo, modo de depuração quando environment == "local"). Mantenha as entradas no ambiente, derivações no código.
Relacionados
- Injeção de Dependência e Conexão - injetando configurações na raiz
- Checklist de Decisão de Arquitetura de Projeto - decisões de configuração antecipadas
- Checklist de Auditoria de Código-Fonte - segredos e sinais de alerta de configuração
- Conflitos de Dependência e Ambiente - depuração de incompatibilidade de ambiente
- Melhores Práticas de Arquitetura - hábitos de configuração
Versões da Stack: Esta página foi escrita para Python 3.14.0 (estável 3.14, manutenção 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+, e uv 0.6+.