Dans l'article précédent, tu as installé dbt, connecté Snowflake et fait tourner un premier modèle. Mais ce modèle, c'était un SELECT avec des valeurs écrites en dur. Sympa pour vérifier que tout marche mais inutile en vrai.
Maintenant on travaille sur de vraies données, en disant à dbt où elles se trouvent (les sources), puis à construire la première couche propre par-dessus (le staging). C'est le socle de tout projet dbt, et ça correspond pile au passage Bronze vers Silver de l'architecture Médaillon.
D'abord, des données brutes dans Snowflake
Pour déclarer des sources, il faut bien que quelque chose existe à la source. Dans un vrai projet, ces données arrivent d'un outil d'ingestion comme par exemple (Fivetran, Airbyte, Talend, Snowpipe) et atterrissent dans un schéma brut. On va simuler ça à la main.
Ouvre une feuille SQL dans Snowsight et crée un schéma raw avec deux tables :
USE ROLE dbt_role;
USE DATABASE analytics;
-- Le schéma qui reçoit les données brutes (la couche Bronze)
CREATE SCHEMA IF NOT EXISTS raw;
-- Table clients
CREATE OR REPLACE TABLE raw.customers (
id INT,
first_name STRING,
last_name STRING,
email STRING,
created_at TIMESTAMP,
_loaded_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP() -- date d'arrivée de la donnée
);
INSERT INTO raw.customers (id, first_name, last_name, email, created_at) VALUES
(1, 'Marc', 'Dubois', 'marc.dubois@email.fr', '2026-01-10'),
(2, 'Sophie', 'Martin', 'sophie.martin@email.fr', '2026-01-12'),
(3, 'Karim', 'Benali', 'karim.benali@email.fr', '2026-02-01');
-- Table commandes
CREATE OR REPLACE TABLE raw.orders (
order_id INT,
customer_id INT,
amount NUMBER(10,2),
status STRING,
order_date DATE,
_loaded_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP()
);
INSERT INTO raw.orders (order_id, customer_id, amount, status, order_date) VALUES
(101, 1, 49.90, 'completed', '2026-02-15'),
(102, 1, 19.90, 'completed', '2026-03-02'),
(103, 2, 99.00, 'pending', '2026-03-10'),
(104, 3, 14.99, 'completed', '2026-03-12');
Voilà ta couche brute. Des données telles qu'elles arrivent. La colonne _loaded_at nous servira plus loin pour la fraîcheur.

Déclarer les sources
On pourra écrire FROM analytics.raw.customers directement dans les modèles mais c'est une très mauvaise idée. Le jour où le schéma change de nom, tu dois modifier tous tes fichiers un par un. dbt règle ça avec les sources : tu déclares une fois où se trouvent les données brutes, et tu y fais référence par un nom logique.
Dans ton projet, crée un dossier models/staging/ et dedans un fichier _sources.yml :
version: 2
sources:
- name: raw
database: analytics
schema: raw
tables:
- name: customers
- name: orders
Tu viens de dire à dbt : "la source raw pointe vers analytics.raw, et elle contient les tables customers et orders". À partir de là, dans tes modèles, tu n'écris plus jamais le chemin physique. Tu écris :
SELECT * FROM {{ source('raw', 'customers') }}
dbt traduit ça tout seul en analytics.raw.customers au moment de l'exécution. Si demain la source change, on va changer une ligne dans le YAML et c'est réglé partout.
La couche staging
La couche staging, c'est la première transformation. Une règle simple : un modèle de staging par table source, et on y fait du nettoyage léger seulement. Renommer les colonnes, caster les types, harmoniser les formats. Pas de jointure, pas d'agrégat, pas de logique métier. Ça vient après.
Crée models/staging/stg_customers.sql :
with source as (
select * from {{ source('raw', 'customers') }}
),
renamed as (
select
id as customer_id,
first_name as prenom,
last_name as nom,
lower(email) as email,
created_at as date_creation
from source
)
select * from renamed
Puis models/staging/stg_orders.sql :
with source as (
select * from {{ source('raw', 'orders') }}
),
renamed as (
select
order_id,
customer_id,
amount as montant,
status as statut,
order_date as date_commande
from source
)
select * from renamed
Le pattern with source as (...) , renamed as (...) est une convention dbt très répandue. Ça rend le modèle lisible car on voit d'un coup d'où vient la donnée et ce qu'on en fait. Si les CTE ne te parlent pas, j'en ai fait un article dédié.
Le nommage stg_
stg_. C'est une norme de la communauté dbt et pas une obligation technique. Mais elle te sauve la vie quand ton projet grossit car d'un coup d'oeil tu sais qu'un modèle stg_orders est une couche d'entrée brute, pas un modèle métier. On range même chaque système source dans son sous-dossier : staging/stripe/, staging/salesforce/ et on ne mélange pas tout dans la racineref() pour chaîner les modèles
Tu sais référencer une source avec source(). Pour référencer un autre modèle dbt, tu utilises ref(). Et c'est le coeur de dbt car c'est avec cela qu'il construit le graphe de dépendances et qui détermine dans quel ordre tout s'exécute.
Crée un dossier models/marts/ et un modèle mart_clients_commandes.sql qui combine tes deux modèles de staging :
with clients as (
select * from {{ ref('stg_customers') }}
),
commandes as (
select * from {{ ref('stg_orders') }}
)
select
c.customer_id,
c.prenom,
c.nom,
count(o.order_id) as nb_commandes,
sum(o.montant) as total_depense
from clients c
left join commandes o
on c.customer_id = o.customer_id
group by 1, 2, 3
Remarque qu'on n'écrit jamais le nom physique d'une table. On passe par ref('stg_customers'), jamais par analytics.dev.stg_customers. C'est ça qui permet à dbt de savoir que `mart_clients_commandes` dépend de stg_customers et stg_orders, et donc de les construire avant.
Lance tout :
dbt run
dbt construit tes trois modèles dans le bon ordre : d'abord les deux staging, puis le mart qui en dépend. Tu n'as rien ordonné toi-même, il a lu les ref() et déduit le graphe. Va voir dans Snowsight, déplie ANALYTICS > DEV : tes trois vues sont là.

Tu peux supprimer lemon_premier_modele.sqlde l'article précédent, il ne sert plus à rien. Garde ton dossiermodels/propre dès le début.
Vérifier que tes sources sont à jour
Un pipeline qui tourne sur des données périmées, c'est pire qu'un pipeline en erreur, parce que personne ne s'en rend compte. dbt sait surveiller la fraîcheur de tes sources grâce à la colonne _loaded_at qu'on a prévue.
Complète ton _sources.yml :
version: 2
sources:
- name: raw
database: analytics
schema: raw
tables:
- name: customers
- name: orders
config:
loaded_at_field: _loaded_at
freshness:
warn_after: {count: 12, period: hour}
error_after: {count: 24, period: hour}Puis lance :
dbt source freshness
dbt regarde la valeur max de _loaded_at dans raw.orders. Si la donnée la plus récente a plus de 12 heures, il te met un warning. Plus de 24 heures, une erreur. En prod, tu branches cette commande sur ton orchestrateur et tu es prévenu dès qu'une source arrête d'être alimentée.
Le lien avec l'architecture Médaillon
Si tu as lu mon article sur le Médaillon, tu as déjà reconnu le schéma :
| Couche Médaillon | Dans dbt | Ce qu'on y fait |
|---|---|---|
| Bronze | les sources (raw) |
donnée brute, jamais modifiée |
| Silver | le staging (stg_) |
nettoyage léger, renommage, cast |
| Gold | les marts | logique métier, agrégats, modèles finaux |
Ton mart_clients_commandes est un premier pas vers la couche Gold. On le construira proprement plus tard, avec des dimensions et des faits. Pour l'instant retiens la logique : la donnée brute reste intacte, et chaque couche fait une seule chose.
Ce qu'on a fait, et la suite
Récap. de ce qu'on a vu dans cet article :
- Créer une couche brute
rawdans Snowflake (le Bronze) - Déclarer les sources dans
_sources.ymlet utilisésource() - Construire des modèles de staging
stg_avec un nettoyage léger (le Silver) - Chainer les modèles avec
ref()et laissé dbt gérer l'ordre - Mettre en place un contrôle de fraîcheur avec
dbt source freshness.
Tu as maintenant un vrai projet structuré en couches. Dans le prochain article, on s'attaque aux matérialisations et pourquoi les modèles sont des vues par défaut, quand les transformer en tables, et comment dbt gère tout ça avec un seul mot-clé.
Aller plus loin
Cet article fait partie de la formation dbt complète, du premier modèle au déploiement en production.
👉 Suivre toute la formation dbt
dbt tourne sur Snowflake dans ce parcours. Pour maîtriser le socle (warehouses, rôles, ingestion) :
👉 Accéder à la formation Snowflake
Et pour t'entraîner sur dbt en conditions d'examen, la certification dbt Analytics Engineering teste exactement ces concepts de sources, staging et ref().
👉 Préparer la certification dbt sur DataCertification.fr
Tu veux que je t'accompagne sur ton projet data (Snowflake, dbt, modélisation, industrialisation) ?
👉 Réserver un appel de 30 minutes
Questions fréquentes
Quelle différence entre source() et ref() en dbt ?
source() pointe vers une table brute externe, déclarée dans un fichier sources YAML, que dbt ne construit pas lui-même. ref() pointe vers un autre modèle dbt, c'est-à-dire une table ou une vue que dbt fabrique. La règle simple : source() pour entrer la donnée dans le projet, ref() pour relier les modèles entre eux.
Faut-il un modèle de staging pour chaque table source ?
Oui, c'est la bonne pratique. Un modèle de staging par table source, avec uniquement du nettoyage léger : renommage, cast de types, harmonisation. Toute la logique métier, les jointures et les agrégats viennent dans les couches suivantes. Ça garde chaque modèle simple et réutilisable.
C'est quoi la convention de nommage stg_ en dbt ?
Préfixer les modèles de staging par stg_ est une norme de la communauté dbt. Elle n'a aucun effet technique mais rend le projet lisible : on identifie immédiatement une couche d'entrée. Quand le projet grossit, on range aussi chaque système source dans son propre sous-dossier de staging.
Comment vérifier que mes données sources sont à jour ?
dbt propose un contrôle de fraîcheur. Tu déclares un champ horodaté avec loaded_at_field et des seuils warn_after et error_after dans ton fichier sources, puis tu lances dbt source freshness. dbt compare la valeur la plus récente de ce champ à l'heure actuelle et t'alerte si la source n'est plus alimentée.
Quel est le lien entre les sources dbt et l'architecture Médaillon ?
Les sources dbt correspondent à la couche Bronze (donnée brute non modifiée), les modèles de staging à la couche Silver (donnée nettoyée et normalisée), et les marts à la couche Gold (logique métier et modèles finaux). dbt est l'outil qui matérialise ce passage d'une couche à l'autre.

