dbt-core : transformer ses données SQL — tutoriel 2026
Article pilier : Data engineering self-hosted 2026 — guide complet
Cet article fait partie d’un cluster sur la stack data moderne auto-hébergée. Pour la vue d’ensemble (Airbyte, dbt, Dagster, Iceberg), commencez par le pilier.
Introduction
Vous avez chargé vos données brutes dans Postgres ou DuckDB grâce à Airbyte. Elles arrivent telles quelles : colonnes mal nommées, doublons, jointures non effectuées, agrégats absents. Votre dashboard BI ne peut pas consommer ce chaos directement. C’est exactement le problème que dbt-core résout : transformer, nettoyer et structurer vos données à l’intérieur de votre entrepôt, uniquement en SQL pur, avec versioning Git, tests automatisés et documentation générée à la volée.
dbt-core est la version open source et gratuite du projet dbt Labs. Elle s’installe en Python, fonctionne en ligne de commande et n’impose aucune infrastructure supplémentaire : pas de serveur dédié, pas de cluster Spark, pas d’abonnement cloud obligatoire. Pour une PME à Dakar, Abidjan ou Bamako qui veut construire une couche analytique fiable sur un VPS de 20 €/mois, c’est un outil de premier plan. Ce tutoriel vous emmène de l’installation jusqu’aux macros et packages avancés, en passant par la structure de projet recommandée par dbt Labs elle-même.
Prérequis
- Python 3.10 ou supérieur installé et accessible en ligne de commande (
python --version) - pip à jour (
pip install --upgrade pip) - Un entrepôt de données : Postgres 13+ (recommandé pour la production) ou DuckDB 1.1+ (excellent pour débuter localement sans serveur)
- Git installé — dbt est conçu pour fonctionner dans un dépôt versionné
- Niveau : intermédiaire — vous savez écrire du SQL, vous avez déjà utilisé un terminal
- Temps estimé : environ 30 à 45 minutes pour parcourir toutes les étapes
Étape 1 — Concept ELT vs ETL, et le rôle des models
Avant d’écrire la moindre commande, il est utile de comprendre pourquoi dbt existe et quelle philosophie il incarne. Pendant des années, la transformation des données suivait le schéma ETL (Extract, Transform, Load) : on extrayait les données de la source, on les transformait dans un outil externe (Python, Java, Spark), puis on chargeait le résultat propre dans l’entrepôt. Ce modèle fonctionne, mais il souffre d’un défaut majeur : la transformation vit en dehors de l’entrepôt, dans un autre outil, avec un autre langage, souvent géré par une autre équipe.
dbt incarne la philosophie ELT (Extract, Load, Transform) : on charge d’abord les données brutes dans l’entrepôt (c’est le rôle d’Airbyte dans notre stack), puis on transforme à l’intérieur de l’entrepôt, en SQL pur. L’entrepôt moderne — Postgres, DuckDB, BigQuery, Snowflake — est suffisamment puissant pour effectuer ces transformations efficacement. SQL est un langage universel que les analysts comprennent déjà. dbt ajoute par-dessus ce SQL les mécanismes qui manquaient : dépendances entre requêtes, tests de qualité, documentation, et exécution reproductible.
La brique de base dans dbt s’appelle un model. Un model, c’est simplement un fichier .sql qui contient un SELECT. dbt se charge de créer la vue ou la table correspondante dans votre entrepôt. Vous référencez un autre model via la fonction ref() — dbt construit automatiquement le graphe de dépendances (le DAG) et exécute tout dans le bon ordre. Voilà le coeur du produit.
Étape 2 — Installer dbt-core et l’adaptateur
dbt-core est le moteur central, mais il ne sait pas parler à votre base de données seul : il faut lui adjoindre un adaptateur spécifique à votre entrepôt. Depuis la version 1.8, dbt-core et les adaptateurs sont découplés — installer l’adaptateur n’installe plus dbt-core automatiquement, et vice-versa. Il faut donc toujours installer les deux explicitement.
Commencez par créer un environnement virtuel Python pour isoler les dépendances de votre projet dbt des autres projets Python sur votre machine :
# Créer et activer un environnement virtuel
python -m venv .venv
source .venv/bin/activate # Linux / macOS
# .venv\Scripts\activate # Windows
# Mettre pip à jour dans l'environnement
pip install --upgrade pip
Ensuite, installez dbt-core avec l’adaptateur de votre choix. Pour Postgres, qui est l’entrepôt le plus courant en production auto-hébergée :
pip install dbt-core dbt-postgres
Si vous préférez démarrer localement sans serveur de base de données, DuckDB est une excellente option — c’est une base analytique embarquée, rapide, qui ne nécessite aucune installation serveur :
pip install dbt-core dbt-duckdb
Vérifiez que l’installation a réussi en interrogeant la version installée. La commande suivante doit retourner dbt-core 1.9.x (la version courante au moment de la rédaction de cet article est la 1.9.10, sortie en août 2025) :
dbt --version
Si vous obtenez un message command not found, c’est que l’environnement virtuel n’est pas activé, ou que le répertoire bin/ de votre venv n’est pas dans le PATH. Activez le venv et réessayez.
Étape 3 — Initialiser le projet dbt et configurer profiles.yml
Une fois dbt installé, l’initialisation d’un projet crée la structure de fichiers standard. Cette commande est à lancer une seule fois, dans le répertoire où vous souhaitez héberger votre projet :
dbt init mon_projet_data
dbt vous demande interactivement quel adaptateur vous utilisez (entrez postgres ou duckdb selon votre choix). Il crée ensuite un répertoire mon_projet_data/ avec la structure suivante : models/ pour vos fichiers SQL, tests/ pour les tests singuliers, macros/ pour vos fonctions SQL réutilisables, seeds/ pour les fichiers CSV statiques à charger, et le fichier dbt_project.yml qui est la configuration centrale du projet.
Le fichier de connexion profiles.yml est séparé du projet — il réside dans ~/.dbt/profiles.yml (dans votre répertoire utilisateur, pas dans le répertoire du projet). Ce choix est délibéré : vos identifiants de connexion ne doivent jamais être versionnés dans Git. Voici un exemple complet pour Postgres :
# ~/.dbt/profiles.yml
mon_projet_data:
target: dev
outputs:
dev:
type: postgres
host: localhost
port: 5432
user: dbt_user
password: motdepasse_securise
dbname: analytics_db
schema: dbt_dev # schéma utilisé en développement
threads: 4 # nombre de modèles exécutés en parallèle
Le nom du profil (mon_projet_data) doit correspondre exactement à la valeur profile: dans votre dbt_project.yml. Testez la connexion avec :
cd mon_projet_data
dbt debug
La commande dbt debug vérifie la version de dbt, la validité du fichier dbt_project.yml, et tente une connexion réelle à votre base. Chaque ligne doit se terminer par OK. Si vous voyez une erreur could not connect to server, vérifiez que Postgres est démarré (pg_isready -h localhost) et que l’utilisateur existe bien.
Étape 4 — Premier modèle : staging, intermediate et mart
La structure de projet recommandée par dbt Labs distingue trois couches, chacune avec un rôle précis. Comprendre cette architecture avant d’écrire le premier fichier SQL vous évitera de nombreux refactorisations ultérieures.
La couche staging est la première transformation appliquée aux données brutes. Elle ne fait que nettoyer et renommer : on standardise les noms de colonnes, on caste les types, on renomme les identifiants. Les models de staging sont généralement matérialisés en view car ils ne représentent pas des artefacts finaux — ce sont des blocs atomiques de construction. On crée un model staging par table source.
Créez le fichier models/staging/stg_ventes.sql :
-- models/staging/stg_ventes.sql
-- Standardise la table brute des ventes chargée par Airbyte
with source as (
select * from {{ source('raw', 'ventes') }}
),
renomme as (
select
id_vente::bigint as vente_id,
date_transaction::date as date_vente,
upper(trim(code_client)) as client_code,
montant_fcfa::numeric(15, 2) as montant_fcfa,
statut as statut_vente,
created_at::timestamp as cree_le
from source
where id_vente is not null -- filtre les lignes corrompues
)
select * from renomme
Notez la fonction {{ source('raw', 'ventes') }} : elle référence une source déclarée dans un fichier YAML (models/staging/sources.yml), ce qui permet à dbt de tracer la lignée des données depuis l’origine jusqu’au mart final. La couche intermediate agrège et joint plusieurs models staging pour préparer les concepts métier. Créez models/intermediate/int_ventes_par_jour.sql :
-- models/intermediate/int_ventes_par_jour.sql
-- Agrège les ventes quotidiennes par client
with ventes as (
select * from {{ ref('stg_ventes') }}
),
agrege as (
select
date_vente,
client_code,
count(vente_id) as nb_transactions,
sum(montant_fcfa) as total_fcfa
from ventes
where statut_vente = 'VALIDE'
group by 1, 2
)
select * from agrege
La fonction {{ ref('stg_ventes') }} est le coeur de dbt : elle dit au moteur que ce model dépend de stg_ventes, et dbt exécutera toujours le staging avant l’intermediate. Enfin, la couche mart expose des tables prêtes pour le BI, matérialisées en table ou incremental. Créez models/marts/finance/fct_ventes_mensuel.sql :
-- models/marts/finance/fct_ventes_mensuel.sql
-- Table de faits mensuelle consommée par le dashboard DG
{{ config(materialized='table') }}
with journalier as (
select * from {{ ref('int_ventes_par_jour') }}
),
mensuel as (
select
date_trunc('month', date_vente)::date as mois,
client_code,
sum(nb_transactions) as nb_transactions,
sum(total_fcfa) as chiffre_affaires_fcfa
from journalier
group by 1, 2
)
select * from mensuel
Exécutez l’ensemble de la chaîne avec :
dbt run
dbt affiche chaque model au fur et à mesure de son exécution, avec le temps écoulé. Un OK en vert signifie que la vue ou la table a été créée avec succès dans votre entrepôt. Si un model échoue, dbt affiche le message d’erreur SQL exact et continue les autres models indépendants — il n’arrête pas tout le pipeline.
Étape 5 — Tests de qualité : uniqueness, not_null, relationships
Un pipeline de données sans tests est un pipeline qu’on ne peut pas faire confiance. dbt intègre nativement quatre types de tests génériques — unique, not_null, accepted_values et relationships — qui s’expriment en YAML plutôt qu’en code, ce qui les rend accessibles aux analysts même non-développeurs.
Créez le fichier models/staging/schema.yml pour déclarer les tests sur le model staging :
# models/staging/schema.yml
version: 2
models:
- name: stg_ventes
description: "Table des ventes brutes nettoyée — une ligne par transaction"
columns:
- name: vente_id
description: "Identifiant unique de la transaction"
tests:
- unique
- not_null
- name: client_code
description: "Code client normalisé (majuscules, sans espaces)"
tests:
- not_null
- name: statut_vente
description: "Statut de la vente"
tests:
- accepted_values:
values: ['VALIDE', 'ANNULE', 'EN_ATTENTE']
Pour les tests de relationships (intégrité référentielle), ajoutez dans le fichier YAML du mart :
- name: fct_ventes_mensuel
columns:
- name: client_code
tests:
- not_null
- relationships:
to: ref('stg_clients')
field: client_code
Lancez tous les tests avec :
dbt test
dbt exécute chaque test comme une requête SQL en coulisse : un unique vérifie l’absence de doublons, un not_null vérifie qu’aucune valeur nulle ne passe, un relationships vérifie que chaque valeur de la colonne existe dans la table référencée. Si un test échoue, dbt affiche le nombre de lignes incriminées et la requête SQL qui a produit ce résultat — ce qui facilite considérablement le débogage. Intégrez dbt test dans votre pipeline CI/CD pour bloquer toute mise en production d’un model qui violerait ses propres contrats de données.
Étape 6 — Documentation automatique et dbt docs serve
L’un des avantages les moins connus de dbt est sa capacité à générer un site de documentation complet à partir des descriptions YAML que vous avez déjà écrites. Cette documentation inclut le DAG interactif (le graphe de dépendances entre tous vos models), les descriptions des colonnes, les résultats des tests et la lignée des données depuis la source jusqu’aux marts.
Générez la documentation statique avec :
dbt docs generate
Cette commande interroge votre entrepôt pour récupérer les métadonnées (noms de colonnes, types) et les combine avec vos descriptions YAML pour produire un catalogue complet dans le répertoire target/. Ensuite, pour servir ce site localement :
dbt docs serve --port 8080
Ouvrez votre navigateur sur http://localhost:8080. Vous accédez à un portail de documentation interactif : à gauche, l’arborescence de tous vos models, sources, seeds et snapshots ; à droite, la description du model sélectionné, ses colonnes avec types et tests, et en bas, le graphe de lignée visuel. C’est un outil extrêmement précieux pour les équipes qui onboardent de nouveaux analysts ou qui doivent justifier leur architecture de données lors d’un audit. En production, vous pouvez exposer ce site derrière un Nginx avec authentification basique.
Étape 7 — Macros et packages dbt-utils
Les macros dans dbt sont l’équivalent des fonctions en programmation : des blocs de SQL réutilisables écrits en Jinja, le langage de templates Python que dbt utilise pour étendre SQL. Une macro s’écrit dans le répertoire macros/ et s’appelle depuis n’importe quel model.
Voici un exemple de macro utile dans le contexte ouest-africain — arrondir un montant selon les règles SYSCOHADA :
-- macros/arrondi_fcfa.sql
{% macro arrondi_fcfa(colonne) %}
round({{ colonne }}::numeric, 0)
{% endmacro %}
Vous l’appelez ensuite dans un model SQL comme n’importe quelle fonction :
select
vente_id,
{{ arrondi_fcfa('montant_fcfa') }} as montant_arrondi
from {{ ref('stg_ventes') }}
Au-delà des macros maison, l’écosystème dbt dispose d’un gestionnaire de packages. Le package le plus utilisé est dbt-utils, publié par dbt Labs, qui fournit des macros prêtes à l’emploi pour des besoins courants. Pour l’installer, créez le fichier packages.yml à la racine du projet :
# packages.yml
packages:
- package: dbt-labs/dbt_utils
version: ">=1.3.0"
Installez les packages déclarés avec :
dbt deps
Une fois installé, vous accédez à des macros comme dbt_utils.generate_surrogate_key() pour créer des clés primaires composites, dbt_utils.date_spine() pour générer des séries temporelles complètes (très utile pour les rapports mensuels sans trous), ou dbt_utils.pivot() pour pivoter des colonnes en lignes. La liste complète est disponible sur hub.getdbt.com.
Erreurs fréquentes
| Erreur | Cause probable | Solution |
|---|---|---|
Profile not found |
Le nom du profil dans dbt_project.yml ne correspond pas au nom dans profiles.yml |
Vérifier que les deux noms sont identiques (sensible à la casse) |
relation does not exist |
Un model référencé via ref() n’a pas encore été exécuté, ou son nom est mal orthographié |
Lancer dbt run --select +mon_model pour exécuter le model et toutes ses dépendances amont |
Compilation Error: source not found |
La source référencée via source() n’est pas déclarée dans un fichier sources.yml |
Créer ou corriger le fichier sources.yml dans le répertoire staging |
Test unique échoue |
La table source contient des doublons sur la clé primaire supposée | Investiguer avec dbt test --store-failures puis requêter la table dbt_test__audit créée automatiquement |
DependencyError: dbt-core not installed lors de l’install d’un adaptateur |
Depuis v1.8, l’adaptateur et dbt-core sont découplés | Installer explicitement pip install dbt-core dbt-postgres (les deux en même temps) |
| Models exécutés dans le mauvais ordre | Utilisation de noms de tables hardcodés au lieu de ref() |
Remplacer toutes les références brutes par {{ ref('nom_model') }} pour que dbt construise le DAG correct |
Adaptation au contexte ouest-africain
dbt-core prend toute sa dimension dans les PME et moyennes entreprises d’Afrique de l’Ouest qui ont besoin de transformer leurs données opérationnelles en informations décisionnelles, sans pour autant disposer d’une équipe data de dix personnes. Voici quatre cas d’usage concrets qui résonnent avec les réalités locales.
Modèles de factures SYSCOHADA. Le plan comptable SYSCOHADA impose des nomenclatures spécifiques : comptes à 4 ou 6 chiffres, libellés standardisés, distinctions entre charges d’exploitation et charges financières. Un projet dbt peut encapsuler toute cette logique dans des models staging (un par table de votre logiciel ERP — Sage, Odoo, ou tableur Excel chargé via Airbyte) et des models mart qui produisent automatiquement les agrégats nécessaires à l’établissement des états financiers annuels. Chaque model SQL constitue une trace auditée de la transformation : vous pouvez montrer exactement comment le chiffre d’affaires du bilan a été calculé, colonne par colonne, model par model, sans jamais ouvrir un fichier Excel.
Agrégats journaliers Mobile Money. Les transactions Orange Money, Wave ou Moov Africa arrivent souvent comme des exports CSV bruts ou des webhooks stockés en base. Avec dbt, vous construisez un model staging qui normalise chaque transaction (montant, frais, statut, numéro MSISDN anonymisé), un model intermediate qui agrège par jour et par type de transaction, et un mart qui alimente le tableau de bord du directeur financier. La cadence journalière peut être automatisée avec Dagster (un autre outil du cluster) qui appelle dbt run chaque matin à 6h.
Lignée de données pour audit OHADA. Lors d’un audit légal ou fiscal, le commissaire aux comptes peut demander la traçabilité d’un chiffre financier. Avec dbt, la commande dbt docs generate produit instantanément le graphe de lignée complet : de la table brute source jusqu’à la ligne du rapport final, chaque transformation SQL est documentée, versionnée dans Git et horodatée. C’est un argument concret pour convaincre votre direction d’investir dans cette infrastructure.
Tests de qualité avant le dashboard du DG. Rien n’est plus dommageable pour la crédibilité d’une équipe data que de présenter au directeur général un tableau de bord avec des chiffres incohérents. En ajoutant des tests not_null sur toutes les colonnes de montants et des tests unique sur les identifiants de transactions, vous créez un filet de sécurité automatique : si un export contient des doublons ou des montants nuls, dbt test échoue et le pipeline s’arrête avant la mise à jour du dashboard. Le DG ne voit jamais de données corrompues.
Tutoriels frères
- Airbyte : ingérer ses données sans coder — tutoriel 2026 — mettre en place la couche EL avant dbt
- Dagster : orchestrer ses pipelines data — tutoriel 2026 — automatiser l’exécution de dbt en production
- Apache Iceberg : format de table ouvert pour le data lake — tutoriel 2026 — stocker les données transformées dans un format pérenne
Pour aller plus loin
- Retour au pilier : Data engineering self-hosted 2026 — guide complet
- Documentation officielle dbt — référence exhaustive sur toutes les fonctionnalités
- github.com/dbt-labs/dbt-core — code source, issues et releases officielles
- hub.getdbt.com — annuaire de tous les packages dbt disponibles
- Guide officiel de structure de projet dbt — staging, intermediate, marts en détail
- Prochaine étape suggérée : configurer les snapshots dbt pour historiser les données qui changent (SCD Type 2) — particulièrement utile pour les statuts de commandes ou les tarifs Mobile Money
FAQ
Q : dbt-core est-il vraiment gratuit, ou faut-il passer à dbt Cloud pour avoir toutes les fonctionnalités ?
R : dbt-core est 100 % open source (licence Apache 2.0) et contient toutes les fonctionnalités de transformation : models, tests, documentation, macros, packages, snapshots, seeds. dbt Cloud est le service SaaS payant de dbt Labs qui ajoute une interface graphique, une planification native, une CI/CD intégrée et le support. Pour une PME qui a déjà Dagster ou un simple cron, dbt-core seul suffit largement.
Q : Quelle est la différence entre un modèle view et un modèle table dans dbt ?
R : Quand un model est configuré en view (vue, la valeur par défaut), dbt crée une vue SQL dans votre entrepôt — la requête est exécutée à chaque fois que quelqu’un interroge la vue. C’est léger et toujours à jour, mais lent si la requête est complexe. Quand un model est configuré en table, dbt recrée physiquement la table à chaque dbt run — c’est plus rapide à l’interrogation mais prend plus de place et de temps à reconstruire. Il existe également la matérialisation incremental qui n’ajoute que les nouvelles lignes, idéale pour les grandes tables de transactions.
Q : Est-ce que dbt fonctionne avec MySQL ou SQLite, des bases courantes en Afrique de l’Ouest ?
R : Il existe des adaptateurs communautaires pour MySQL (dbt-mysql) et d’autres bases, mais ils sont moins maintenus que les adaptateurs officiels (Postgres, DuckDB, BigQuery, Snowflake, Databricks). Pour une nouvelle infrastructure, il vaut mieux partir sur Postgres — gratuit, robuste, parfaitement supporté par dbt — plutôt que MySQL. SQLite n’est pas supporté ; DuckDB est la meilleure alternative pour un environnement local sans serveur.
Q : Comment intégrer dbt dans un pipeline CI/CD avec GitHub Actions ?
R : Vous créez un workflow GitHub Actions qui s’exécute à chaque pull request, installe les dépendances Python, configure profiles.yml depuis les secrets GitHub, puis exécute dbt deps && dbt build. La commande dbt build combine dbt run et dbt test en une seule passe. Si un test échoue, le workflow échoue et la PR ne peut pas être mergée — c’est une protection automatique de la qualité des données.
Q : dbt peut-il se connecter directement à des APIs ou des fichiers CSV locaux ?
R : Non — dbt ne se connecte qu’à des entrepôts SQL. Pour les APIs et les CSV, utilisez Airbyte (ou un script Python simple) pour charger d’abord les données dans votre entrepôt Postgres ou DuckDB. dbt prend ensuite le relais pour les transformer. En revanche, pour les petits fichiers CSV de référence (nomenclatures, codes pays UEMOA, catégories SYSCOHADA), la fonctionnalité dbt seed permet de charger ces fichiers directement dans l’entrepôt en une commande : dbt seed.
Q : Combien de temps faut-il pour former un analyst SQL à dbt ?
R : Un analyst qui écrit du SQL quotidiennement sera productif sur dbt en deux à trois jours. La courbe d’apprentissage est faible parce que le coeur du produit, c’est du SQL avec quelques fonctions Jinja (ref(), source(), config()). Les concepts avancés (macros complexes, materializations incrementales, snapshots) demandent une à deux semaines supplémentaires. dbt Labs propose également un parcours de formation gratuit sur courses.getdbt.com.