| name | dbt-guide |
| description | Transformation de données avec dbt — models, tests, sources, macros et documentation automatisée. Se déclenche avec "dbt", "data build tool", "dbt model", "dbt test", "transformation de données dbt". Also triggers on "dbt models", "dbt tests", "transform data with dbt". |
Guide dbt
Workflow
1. Initialiser et structurer le projet
dbt init mon_projet
cd mon_projet
dbt debug
Arborescence cible :
models/
staging/ ← nettoyage source, renommage, cast ; materialisation = view
intermediate/ ← jointures, logique métier complexe ; materialisation = view ou ephemeral
marts/ ← modèles finaux consommables ; materialisation = table
macros/
tests/
seeds/
snapshots/
dbt_project.yml — materialisations par dossier :
models:
mon_projet:
staging:
+materialized: view
+schema: staging
intermediate:
+materialized: view
marts:
+materialized: table
+schema: marts
2. Déclarer les sources
version: 2
sources:
- name: raw_crm
schema: raw
freshness:
warn_after: {count: 12, period: hour}
error_after: {count: 24, period: hour}
loaded_at_field: _loaded_at
tables:
- name: orders
description: "Commandes brutes issues du CRM"
columns:
- name: order_id
tests: [unique, not_null]
Référencer dans un modèle :
select * from {{ source('raw_crm', 'orders') }}
Tester la fraîcheur :
dbt source freshness
3. Développer les modèles
Staging — un modèle par table source, préfixe stg_ :
with source as (
select * from {{ source('raw_crm', 'orders') }}
),
renamed as (
select
order_id::varchar as order_id,
customer_id::int as customer_id,
created_at::timestamp as created_at,
status::varchar as status
from source
)
select * from renamed
Mart — utilise ref() pour chaque dépendance :
with orders as (
select * from {{ ref('stg_orders') }}
),
customers as (
select * from {{ ref('stg_customers') }}
)
select
o.order_id,
o.created_at,
c.customer_name,
o.status
from orders o
left join customers c on o.customer_id = c.customer_id
Critères de choix de materialisation :
| Cas | Materialisation recommandée |
|---|
| Nettoyage léger / peu consommé | view |
| Rapport BI / dashboard | table |
| Table > 10M lignes avec clé temporelle | incremental |
| Sous-requête intermédiaire réutilisée | ephemeral |
| Suivi de changements type SCD2 | snapshot |
Modèle incrémental :
{{ config(materialized='incremental', unique_key='event_id') }}
select * from {{ ref('stg_events') }}
{% if is_incremental() %}
where event_at > (select max(event_at) from {{ this }})
{% endif %}
4. Tester les données
Fichier YAML associé à chaque modèle :
version: 2
models:
- name: fct_orders
description: "Faits commandes enrichis"
columns:
- name: order_id
tests: [unique, not_null]
- name: status
tests:
- accepted_values:
values: ['pending', 'confirmed', 'shipped', 'cancelled']
- name: customer_id
tests:
- relationships:
to: ref('stg_customers')
field: customer_id
Test custom SQL dans tests/ :
select order_id
from {{ ref('fct_orders') }}
where amount < 0
Commandes :
dbt test
dbt test --select fct_orders
dbt test --store-failures
5. Créer des macros
{% macro generate_surrogate_key(fields) %}
{{ dbt_utils.generate_surrogate_key(fields) }}
{% endmacro %}
{% macro audit_columns() %}
current_timestamp as dbt_loaded_at,
'{{ invocation_id }}' as dbt_run_id
{% endmacro %}
Usage dans un modèle :
select
{{ generate_surrogate_key(['order_id', 'customer_id']) }} as sk_order,
order_id,
{{ audit_columns() }}
from {{ ref('stg_orders') }}
6. Documenter
models:
- name: fct_orders
description: >
Faits commandes joints avec les clients.
Utilisé par le dashboard Revenue dans Metabase.
columns:
- name: order_id
description: "Identifiant unique de la commande (source CRM)"
dbt docs generate
dbt docs serve
7. CI/CD et environnements
profiles.yml — deux targets :
mon_projet:
target: dev
outputs:
dev:
type: snowflake
schema: "dbt_{{ env_var('DBT_USER', 'dev') }}"
...
prod:
type: snowflake
schema: marts
...
Pipeline CI (GitHub Actions) :
- run: dbt build --target prod --select state:modified+
- run: dbt test --target prod --select state:modified+
dbt build
dbt build --select +fct_orders
dbt run --exclude tag:slow
Anti-patterns / Pièges
| Piège | Correction |
|---|
select * en mart sans liste explicite | Lister les colonnes exposées, ça évite les régressions silencieuses |
| Table en dur dans un modèle SQL | Toujours {{ ref() }} ou {{ source() }} |
Pas de unique_key sur un incrémental | Crée des doublons à chaque run ; définir unique_key obligatoirement |
| Tests YAML uniquement sur la PK | Tester aussi les FK (relationships), les valeurs acceptées et les colonnes NOT NULL métier |
| Incrémental sans stratégie full refresh | Ajouter +full_refresh: false en dev seulement ; prévoir dbt run --full-refresh planifié |
| Modèles staging qui joinent plusieurs sources | Un modèle staging = une source ; les jointures vont en intermediate/ |
| Documentation rédigée après-coup | Écrire description + tests en même temps que le modèle, sinon jamais fait |
dbt run en prod sans dbt test | Utiliser dbt build qui enchaîne les deux et stoppe à la première erreur |
Bonnes pratiques 2026
- dbt Core ≥ 1.8 : utiliser
dbt_project.yml v10 et les groupes de modèles pour les accès (access: private/protected/public).
- Contrats de modèle (
contract: {enforced: true}) sur les marts exposés — casse le build si le schéma dévie.
- Unit tests dbt (natif depuis 1.8) pour tester la logique SQL sans données réelles :
unit_tests:
- name: test_order_total
model: fct_orders
given:
- input: ref('stg_orders')
rows: [{order_id: 1, amount: 100}, {order_id: 2, amount: 0}]
expect:
rows: [{order_id: 1, total: 100}]
- dbt-utils et dbt-expectations : packages standards pour tests avancés (
expect_column_values_to_be_between, expression_is_true, etc.).
- Semantic Layer dbt : définir les métriques dans
metrics: pour exposer des KPIs cohérents aux outils BI.
- Sélecteur
state:modified+ en CI : ne rebuilder que ce qui a changé, réduit les coûts warehouse jusqu'à 80 %.