Como usar dbt state no CI: 3 passos para cortar custos
Rodar o pipeline inteiro a cada pull request queima créditos caros de computação e paralisa entregas críticas. Usar o dbt state resolve esse gargalo: o mecanismo identifica modelos alterados e processa apenas nós dependentes no DAG. Essa validação seletiva poupa tempo e corta execuções desnecessárias na integração contínua.
O que acontece quando o CI roda sem dbt state?
Em pipelines tradicionais, cada merge request dispara um comando amplo como dbt build. Se o repositório reúne centenas de modelos, o runner compila e executa todas as tabelas. Modelos inalterados rodam novamente sem necessidade. Isso consome processamento e gera custos evitáveis no banco de dados analítico.
Quando cada pull request simples precisa aguardar testes de modelos intocados, a equipe perde tempo em filas ociosas. Manter um pipeline de dados inteligente exige foco: a validação automatizada precisa isolar e compilar apenas o código alterado pelo desenvolvedor.
O método Slim CI elimina esse desperdício operacional. Ele compara o código da branch aberta com os metadados gerados pelo ambiente de produção. O dbt localiza as modificações na topologia do grafo. Somente os nós impactados entram no plano de execução daquela verificação.
Como configurar o Slim CI com dbt state em 3 passos?
A lógica de comparação utiliza dois elementos centrais: o seletor state:modified+ e o modificador --defer. O operador '+' expande a execução para incluir todos os modelos downstream dependentes.
A flag --defer resolve as referências upstream não construídas no teste. Se o modelo modificado consulta uma tabela intermediária estável, o dbt redireciona a consulta diretamente para o schema de produção. Nenhuma tabela intermediária precisa ser recriada ou duplicada no schema temporário de validação.
Passo 1: Salve o arquivo manifest.json de produção. O dbt gera esse artefato em target/manifest.json após a execução de comandos como dbt compile ou dbt build no branch principal. Ao final do job de produção, exporte o arquivo para o bucket com o comando de cópia:
aws s3 cp target/manifest.json s3://meu-bucket-dbt-metadata/manifest.json
O manifesto armazena a estrutura do projeto e serve como referência imutável de comparação.
Passo 2: Baixe o manifesto no runner de CI. Antes de disparar os testes no pull request, copie o manifest.json para uma pasta local, como ./state. O runner precisa desses metadados salvos para calcular a diferença entre as duas versões do repositório.
Passo 3: Dispare o comando com seleção de estado e redirecionamento. O comando abaixo aplica as flags necessárias no ambiente de pull request:
dbt build \
--select state:modified+ \
--state ./state \
--defer \
--target ci
Esse comando localiza as alterações contra o manifesto de referência. Se você alterar apenas um modelo dimensional final, o dbt compilará unicamente essa tabela. As tabelas upstream estáveis serão lidas diretamente do banco produtivo sem reprocessamento.
Quais regras e limitações o dbt impõe na comparação de estado?
A comparação de estado segue critérios técnicos descritos nas regras de comparação de estado do dbt. O dbt armazena o hash dos arquivos de seed com tamanho inferior a 1 MiB para identificar modificações em seu conteúdo. Para arquivos de seed maiores que 1 MiB, o dbt não consegue comparar o conteúdo e emite um aviso.
Configurações no arquivo YAML também orientam o seletor. Alterações em tags e meta não são tratadas como modificações para o estado por representarem apenas metadados que não afetam a materialização. Qualquer outra alteração de configuração é considerada modificação porque pode alterar a materialização do recurso.
Atenção com macros e variáveis no código. O dbt marca como modificado qualquer recurso que dependa diretamente ou indiretamente de uma macro que tenha sofrido alteração. Por outro lado, o dbt não rastreia a linhagem para marcar um modelo como modificado apenas por alteração no valor de variáveis var ou env_var.
Como o Slim CI se compara à execução completa?
A diferença prática aparece no consumo de computação do data warehouse. Validar o grafo inteiro em cada commit sobrecarrega warehouses compartilhados. Ao estruturar armazéns analíticos na nuvem — tema que exploramos no nosso curso gratuito Snowflake —, reduzir o tempo de computação evita o desperdício de créditos.
| Critério de Validação | Execução Completa (dbt build) |
Slim CI (state:modified+) |
|---|---|---|
| Modelos processados | Grafo completo do projeto | Somente nós alterados e dependentes |
| Origem dos dados upstream | Recriados no schema de teste | Apontados para produção via --defer |
| Tempo de feedback | Proporcional ao total de modelos | Restrito aos modelos da branch e linhagem |
| Consumo de computação | Alocado para todas as tabelas | Focado estritamente nas mudanças do commit |
| Fila de integração contínua | Concorrência elevada em horários de pico | Liberação rápida para os desenvolvedores |
A tabela demonstra o contraste na alocação de recursos. Em vez de reconstruir tabelas dimensionais históricas a cada commit, o runner restringe o trabalho às tabelas impactadas. Desenvolvedores recebem feedback ágil sem esperar a reconstrução de dados que já foram validados.
Como estruturar o workflow no GitHub Actions?
Para implementar esse pipeline, configure um workflow de integração contínua no repositório. O arquivo profiles.yml deve residir na raiz do repositório. Como o dbt busca os perfis por padrão em ~/.dbt/profiles.yml, defina a variável DBT_PROFILES_DIR: . no ambiente da execução. O runner também precisa de permissão para ler o bucket de metadados e compilar modelos no schema de teste.
O arquivo YAML abaixo demonstra o fluxo completo e funcional:
name: Slim CI dbt
on:
pull_request:
branches: [ main ]
jobs:
ci:
runs-on: ubuntu-latest
steps:
- name: Checkout do código
uses: actions/checkout@v4
- name: Configurar Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Instalar dbt e adaptador
run: pip install dbt-snowflake
- name: Autenticar na AWS
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: us-east-1
- name: Baixar manifest de producao
run: |
mkdir -p ./state
aws s3 cp s3://meu-bucket-dbt-metadata/manifest.json ./state/manifest.json
- name: Executar Slim CI no Snowflake
env:
DBT_PROFILES_DIR: .
DBT_SNOWFLAKE_ACCOUNT: ${{ secrets.SNOWFLAKE_ACCOUNT }}
DBT_SNOWFLAKE_USER: ${{ secrets.SNOWFLAKE_USER }}
DBT_SNOWFLAKE_PASSWORD: ${{ secrets.SNOWFLAKE_PASSWORD }}
DBT_SNOWFLAKE_ROLE: ${{ secrets.SNOWFLAKE_ROLE }}
DBT_SNOWFLAKE_WAREHOUSE: ${{ secrets.SNOWFLAKE_WAREHOUSE }}
DBT_SNOWFLAKE_DATABASE: ${{ secrets.SNOWFLAKE_DATABASE }}
DBT_SNOWFLAKE_SCHEMA: ${{ secrets.SNOWFLAKE_SCHEMA }}
run: |
dbt deps
dbt build --select state:modified+ --defer --state ./state --target ci
O step de autenticação da AWS fornece permissão temporária para baixar o manifesto antes da compilação. As variáveis de ambiente do Snowflake conectam o dbt via profiles.yml na raiz do projeto configurado com env_var.
A flag --defer resolve o redirecionamento dos ponteiros das dependências upstream para o banco produtivo. A proteção de leitura estrita em produção, porém, depende da concessão de privilégios via GRANT SELECT na role do Snowflake utilizada. Essa configuração de permissões impede gravações acidentais fora do schema temporário de teste.
Abra o repositório do seu projeto agora. Adicione o upload do target/manifest.json na etapa final do pipeline de produção. Em seguida, crie o workflow do GitHub Actions com state:modified+ e teste o primeiro pull request para conferir o tempo reduzido na fila de execução.