Pydantic Settings: configurações seguras

Publicado em: 23/07/2026
Tempo de leitura: 5 minutos
Configurações seguras em aplicação Python com Pydantic Settings

Configurações de aplicação parecem simples enquanto o projeto possui apenas duas ou três variáveis. Porém, quando entram banco de dados, APIs externas, ambientes de desenvolvimento, testes e produção, o código pode virar uma mistura perigosa de valores fixos, chamadas a os.getenv() e verificações espalhadas. O Pydantic Settings resolve esse problema ao reunir as configurações em classes tipadas, validar valores automaticamente e carregar dados de variáveis de ambiente ou arquivos .env.

Neste guia, você aprenderá a criar uma configuração centralizada, declarar tipos, trabalhar com valores obrigatórios, converter listas e URLs, separar ambientes, proteger segredos e integrar tudo a uma aplicação FastAPI. A proposta é transformar configurações frágeis em um componente previsível e fácil de testar.

Por que centralizar configurações?

Um projeto pequeno pode funcionar com chamadas isoladas a os.getenv(). O problema aparece quando cada módulo busca uma variável diferente, aplica um valor padrão próprio ou converte tipos de maneiras inconsistentes. Uma porta pode chegar como texto, um modo de depuração pode ser interpretado incorretamente e uma senha ausente pode causar erro apenas depois que a aplicação já iniciou.

Centralizar as configurações permite validar tudo logo na inicialização. Se um valor obrigatório não existir ou estiver no formato errado, a aplicação falha cedo com uma mensagem clara. Isso reduz erros silenciosos e torna a implantação mais segura. Para entender a base, veja também como ler variáveis de ambiente em Python.

Instalando o Pydantic Settings

Crie um ambiente virtual e instale o pacote:

python -m venv .venv
# Windows: .venv\Scripts\activate
# Linux/macOS: source .venv/bin/activate
pip install pydantic-settings

O pacote utiliza o Pydantic para validar os dados e fornece a classe BaseSettings. Se você ainda não organiza dependências por projeto, vale revisar o guia sobre ambientes virtuais com venv.

Criando a primeira classe de configurações

Crie um arquivo config.py:

from pydantic import SecretStr
from pydantic_settings import BaseSettings, SettingsConfigDict

class Settings(BaseSettings):
    app_name: str = "Minha API"
    debug: bool = False
    port: int = 8000
    database_url: str
    api_key: SecretStr

    model_config = SettingsConfigDict(
        env_file=".env",
        env_file_encoding="utf-8",
        extra="ignore",
    )

settings = Settings()

A classe declara os nomes e os tipos esperados. database_url e api_key são obrigatórios porque não possuem valores padrão. O campo api_key usa SecretStr, que evita mostrar o segredo completo em logs e representações do objeto.

Crie um arquivo .env:

APP_NAME=Academify API
DEBUG=true
PORT=8080
DATABASE_URL=sqlite:///app.db
API_KEY=segredo_local

Ao instanciar Settings, o Pydantic converte true para booleano e 8080 para inteiro. Esse comportamento reduz conversões manuais e documenta o formato esperado diretamente no código.

Como os nomes das variáveis são resolvidos

Por padrão, os campos podem ser preenchidos por variáveis de ambiente com o mesmo nome, sem diferenciar maiúsculas e minúsculas em muitos ambientes. Para adotar um prefixo e evitar conflitos, configure env_prefix:

model_config = SettingsConfigDict(
    env_file=".env",
    env_prefix="APP_",
    extra="ignore",
)

Nesse caso, o campo database_url será lido de APP_DATABASE_URL. Prefixos são úteis quando vários serviços compartilham o mesmo servidor ou arquivo de implantação.

Validando valores

Além de converter tipos, você pode impor limites:

from pydantic import Field

class Settings(BaseSettings):
    port: int = Field(default=8000, ge=1, le=65535)
    workers: int = Field(default=1, ge=1, le=32)
    timeout_seconds: float = Field(default=10.0, gt=0)

Agora uma porta negativa ou um número exagerado de processos será rejeitado imediatamente. Esse estilo se beneficia das anotações explicadas no artigo sobre type hints em Python.

Listas e estruturas mais complexas

Valores complexos podem ser fornecidos em JSON:

from pydantic_settings import BaseSettings

class Settings(BaseSettings):
    allowed_hosts: list[str] = ["localhost"]
    feature_flags: dict[str, bool] = {}

No arquivo .env:

ALLOWED_HOSTS=["academify.com.br", "api.academify.com.br"]
FEATURE_FLAGS={"novo_login": true, "cache": false}

Isso é mais seguro do que dividir textos manualmente por vírgulas, especialmente quando os valores podem conter espaços ou caracteres especiais.

Configurações aninhadas

Projetos maiores ficam mais claros quando as configurações são agrupadas:

from pydantic import BaseModel
from pydantic_settings import BaseSettings, SettingsConfigDict

class DatabaseSettings(BaseModel):
    host: str = "localhost"
    port: int = 5432
    name: str = "app"

class Settings(BaseSettings):
    database: DatabaseSettings = DatabaseSettings()

    model_config = SettingsConfigDict(
        env_nested_delimiter="__"
    )

Com o delimitador duplo, você pode usar DATABASE__HOST e DATABASE__PORT. Esse padrão mantém o objeto organizado sem perder a compatibilidade com variáveis de ambiente.

Integração com FastAPI

Em uma API, evite criar uma nova instância a cada requisição. Use cache:

from functools import lru_cache
from fastapi import Depends, FastAPI

app = FastAPI()

@lru_cache
def get_settings() -> Settings:
    return Settings()

@app.get("/info")
def info(config: Settings = Depends(get_settings)):
    return {
        "app_name": config.app_name,
        "debug": config.debug,
    }

A função é executada apenas uma vez por processo. O padrão combina bem com o tutorial sobre como criar APIs com FastAPI e com o uso de lru_cache em Python.

Separando desenvolvimento, teste e produção

Evite manter um único arquivo com valores para todos os ambientes. Uma estratégia simples é escolher o arquivo por uma variável externa:

import os
from pydantic_settings import SettingsConfigDict

ENV = os.getenv("APP_ENV", "development")

class Settings(BaseSettings):
    model_config = SettingsConfigDict(
        env_file=f".env.{ENV}",
        extra="ignore",
    )

Você pode ter .env.development e .env.test, mas segredos de produção devem ser fornecidos pelo serviço de hospedagem, Docker, Kubernetes ou cofre de segredos. Nunca envie arquivos com credenciais reais ao Git.

Testando configurações

Como a configuração é uma classe, os testes podem substituir valores diretamente:

def test_settings():
    config = Settings(
        database_url="sqlite:///:memory:",
        api_key="teste",
        debug=True,
    )
    assert config.debug is True
    assert config.port == 8000

Também é possível usar o recurso monkeypatch do pytest para definir variáveis temporárias. Isso evita depender do computador do desenvolvedor e deixa os testes reproduzíveis.

Erros comuns

  • Instanciar configurações em muitos módulos: centralize a criação ou use cache.
  • Guardar segredos no repositório: mantenha apenas um arquivo .env.example.
  • Usar texto para tudo: declare bool, int, URLs, listas e tipos específicos.
  • Ignorar falhas de validação: deixe a aplicação falhar cedo quando a configuração estiver inválida.
  • Registrar o objeto completo: mesmo com SecretStr, evite logs desnecessários.
  • Confundir prioridade: variáveis reais de ambiente normalmente devem substituir o arquivo local.

Boas práticas para produção

Mantenha nomes consistentes, documente cada variável em .env.example, aplique o princípio do menor privilégio e rotacione segredos periodicamente. Valide URLs e limites, não apenas a presença do valor. Em contêineres, injete as variáveis no momento da execução. Em pipelines, use o gerenciador de segredos da plataforma e restrinja quem pode visualizar os valores.

A documentação oficial do Pydantic Settings detalha fontes, aliases, configurações aninhadas e personalização. Para entender o tratamento de segredos, consulte também a página de SecretStr.

Conclusão

O Pydantic Settings transforma variáveis de ambiente em uma interface tipada e validada. Em vez de espalhar conversões e valores padrão pelo projeto, você define uma única classe que documenta tudo o que a aplicação precisa. O resultado é um código mais previsível, uma inicialização mais segura e testes mais simples.

Comece com poucos campos, adicione validações relevantes e separe ambientes conforme o projeto crescer. O objetivo não é criar uma configuração complicada, mas garantir que erros de infraestrutura sejam detectados antes de afetarem usuários ou dados.

Compartilhe:

Facebook
WhatsApp
Twitter
LinkedIn

Conteúdo do artigo

    Artigos relacionados

    Desenvolvedor programando em Python com Ruff para lint e formatação
    Boas Práticas
    Foto de perfil de Leandro Hirt da Academify

    Ruff no Python: lint e formatação de código passo a passo

    Aprenda a usar Ruff no Python para lint, formatação, correções automáticas, pyproject.toml, VS Code e CI com uma configuração prática.

    Ler mais

    Tempo de leitura: 10 minutos
    22/07/2026
    Limpeza de dados sujos em Python para data cleaning
    Boas Práticas
    Foto de perfil de Leandro Hirt da Academify

    Como limpar dados sujos no Python: Guia prático de Data Cleaning

    No mundo da programação, existe um ditado muito famoso: “Lixo entra, lixo sai”. Isso significa que, não importa o quão

    Ler mais

    Tempo de leitura: 11 minutos
    12/04/2026
    Proteção de API Flask usando autenticação JWT em Python
    Boas Práticas
    Foto de perfil de Leandro Hirt da Academify

    Como proteger sua API Flask com JWT em minutos

    A segurança é um dos pilares mais importantes no desenvolvimento de aplicações modernas. Quando decidimos Como proteger sua API Flask

    Ler mais

    Tempo de leitura: 9 minutos
    05/04/2026
    Como resolver erros com variáveis de ambiente usando python-dotenv
    Boas Práticas
    Foto de perfil de Leandro Hirt da Academify

    Variáveis .env dão erro? Resolva com python‑dotenv em minutos

    Você já passou pela frustração de configurar um projeto, definir suas chaves de API e, ao rodar o código, receber

    Ler mais

    Tempo de leitura: 10 minutos
    27/03/2026
    Medição de tempo de execução de código Python com timeit
    Boas Práticas
    Foto de perfil de Leandro Hirt da Academify

    Descubra como medir o tempo de código com timeit

    Se você já se perguntou por que um trecho de código demora mais que outro ou se uma alteração realmente

    Ler mais

    Tempo de leitura: 12 minutos
    10/03/2026
    Leitura de variáveis de ambiente em projetos Python
    Boas Práticas
    Foto de perfil de Leandro Hirt da Academify

    Como ler variáveis de ambiente em Python sem erro

    Gerenciar informações sensíveis, como chaves de API, senhas de banco de dados e tokens de acesso, é uma das tarefas

    Ler mais

    Tempo de leitura: 10 minutos
    25/02/2026