Dataform é a ferramenta de transformação de dados integrada nativamente ao BigQuery. Permite definir pipelines de transformação SQL com dependências, testes de qualidade e documentação, tudo versionado em Git.
Foi adquirida pelo Google em 2020 e integrada diretamente ao console do BigQuery em 2022, sem custo adicional além do processamento das queries no BigQuery.
Dataform vs dbt
Ambos resolvem o mesmo problema: organizar e testar transformações SQL no warehouse. As diferenças são principalmente de integração e ecossistema.
| Dataform | dbt | |
|---|---|---|
| Integração GCP | Nativa (console BigQuery, IAM, GitHub) | Via adapter (dbt-bigquery) |
| Linguagem | SQLX (SQL + bloco de config JS) | Jinja + SQL (.sql + .yml) |
| Execução | No próprio console GCP ou via API | CLI local, dbt Cloud ou Airflow |
| Custo | Gratuito (paga só o BigQuery) | dbt Core gratuito; dbt Cloud pago |
| Testes | Assertions (SQL customizado) | Tests genéricos + singular tests |
| Documentação | Automática via tags e descrições | schema.yml com description: |
| Warehouse | Focado em BigQuery | Multi-warehouse (BQ, Snowflake, Redshift…) |
| Comunidade | Menor, mais recente | Grande, madura (pacotes, hub) |
Quando preferir Dataform: time 100% em GCP, quer integração nativa com IAM e console, sem necessidade de manter ambiente dbt separado.
Quando preferir dbt: multi-cloud ou multi-warehouse, time já experiente com dbt, precisa de pacotes da comunidade (dbt-utils, dbt-expectations, etc.).
SQLX: a linguagem do Dataform
SQLX é SQL com um bloco de configuração JavaScript no topo. O Dataform compila SQLX em SQL puro antes de executar no BigQuery.
Tabela simples
-- definitions/trusted/pedidos_diarios.sqlx
config {
type: "table",
schema: "trusted",
description: "Pedidos agregados por dia e região",
tags: ["diario", "pedidos"],
bigquery: {
partitionBy: "data",
clusterBy: ["regiao"]
}
}
SELECT
DATE(criado_em) AS data,
regiao,
COUNT(*) AS qtd_pedidos,
SUM(valor) AS receita
FROM ${ref("staging", "stg_pedidos")}
WHERE status != 'cancelado'
GROUP BY 1, 2O ${ref("schema", "tabela")} é o equivalente ao {{ ref('tabela') }} do dbt: cria a dependência declarativamente e substitui pelo nome completo da tabela no BigQuery.
View
config {
type: "view",
schema: "marts"
}
SELECT * FROM ${ref("pedidos_diarios")}
WHERE data >= DATE_SUB(CURRENT_DATE(), INTERVAL 90 DAY)Tabela incremental
Adiciona apenas os dados novos em vez de recriar a tabela inteira:
config {
type: "incremental",
schema: "trusted",
bigquery: {
partitionBy: "data_evento",
updatePartitionFilter: "data_evento >= DATE_SUB(CURRENT_DATE(), INTERVAL 3 DAY)"
}
}
SELECT
DATE(ts) AS data_evento,
evento_tipo,
usuario_id,
COUNT(*) AS ocorrencias
FROM ${ref("raw", "eventos")}
-- Filtro aplicado apenas em runs incrementais
${when(incremental(), `WHERE ts >= (SELECT MAX(ts) FROM ${self()})`)}
GROUP BY 1, 2, 3Assertions (testes)
Assertions são queries SQL que retornam linhas quando há problemas. Se retornar qualquer linha, o workflow falha:
-- definitions/assertions/pedidos_sem_cliente.sqlx
config {
type: "assertion",
tags: ["qualidade"]
}
-- Falha se existir pedido sem cliente_id
SELECT * FROM ${ref("pedidos_diarios")}
WHERE cliente_id IS NULLDataform também tem assertions inline na config da tabela:
config {
type: "table",
assertions: {
nonNull: ["pedido_id", "cliente_id", "data"],
uniqueKey: ["pedido_id"],
rowConditions: ["valor > 0", "status IN ('ativo', 'cancelado', 'entregue')"]
}
}Declarações (sources externas)
Para referenciar tabelas que não são gerenciadas pelo Dataform (ex: tabelas de ingestão):
-- definitions/sources/raw_pedidos.sqlx
config {
type: "declaration",
schema: "raw",
name: "pedidos",
description: "Pedidos brutos vindos da ingestão via Dataflow"
}Estrutura de um projeto Dataform
dataform/
├── dataform.json ← configuração do projeto (projeto GCP, dataset padrão)
├── definitions/
│ ├── sources/ ← declarações de tabelas externas
│ ├── staging/ ← limpeza e tipagem dos dados brutos
│ ├── trusted/ ← transformações de negócio
│ ├── marts/ ← camada de consumo (BI, APIs)
│ └── assertions/ ← testes de qualidade
├── includes/ ← macros JavaScript reutilizáveis
└── package.json
dataform.json
{
"defaultSchema": "dataform",
"assertionSchema": "dataform_assertions",
"warehouse": "bigquery",
"defaultDatabase": "meu-projeto",
"defaultLocation": "US"
}Macros JavaScript (includes)
Funções reutilizáveis entre arquivos SQLX:
// includes/helpers.js
function formatar_data(coluna) {
return `FORMAT_DATE('%Y-%m', ${coluna})`;
}
function filtro_periodo(coluna, dias) {
return `${coluna} >= DATE_SUB(CURRENT_DATE(), INTERVAL ${dias} DAY)`;
}
module.exports = { formatar_data, filtro_periodo };-- Usar no SQLX
config { type: "view" }
SELECT
${helpers.formatar_data("data_pedido")} AS mes,
SUM(valor) AS receita
FROM ${ref("pedidos")}
WHERE ${helpers.filtro_periodo("data_pedido", 90)}
GROUP BY 1Execução e agendamento
Via console GCP
Workflows são executados pelo console do BigQuery em Dataform > Workspaces. É possível acionar manualmente ou configurar um schedule com frequência e fuso horário.
Via API (para integração com Cloud Composer)
from airflow.providers.google.cloud.operators.dataform import (
DataformCreateCompilationResultOperator,
DataformCreateWorkflowInvocationOperator,
)
compilar = DataformCreateCompilationResultOperator(
task_id="compilar",
project_id="meu-projeto",
region="us-central1",
repository_id="meu-repo",
)
executar = DataformCreateWorkflowInvocationOperator(
task_id="executar",
project_id="meu-projeto",
region="us-central1",
repository_id="meu-repo",
compilation_result=compilar.output,
)
compilar >> executarIntegração com Git
Dataform se conecta nativamente a repositórios GitHub, GitLab e Cloud Source Repositories. Cada workspace é uma branch isolada. O fluxo típico:
flowchart LR W["Workspace - branch feature"] -->|PR| M[Branch main] M -->|schedule| E[Execução no BigQuery] E --> BQ[(BigQuery)]
Ver também: gcp-bigquery | gcp-bigquery-sql | gcp-bigquery-otimizacao | gcp-cloud-composer | gcp-dataplex