> ## Content Index
> Fetch the complete content index at: https://www.idriss-benbassou.com/llms.txt
> Use this file to discover other available public pages before exploring further.

# Les matérialisations dbt : view, table, incremental et ephemeral (et quand choisir quoi)
- URL: https://www.idriss-benbassou.com/dbt-materialisations-view-table-incremental-ephemeral/
- Published: 2026-06-02T08:46:29.000Z
- Updated: 2026-06-12T11:14:37.000Z
- Author: Idriss BENBASSOU
- Tags: dbt, #rating-2

Dans [l'article précédent](https://www.idriss-benbassou.com/dbt-sources-staging-source-ref-premiere-couche/), on a construit trois modèles avec deux en staging et un mart. Et si on va voir dans Snowsight, on remarque un truc et que ce sont tous des vues, pas des tables. On n'a rien demandé de tel, c'est dbt qui a choisi par défaut.

Pourquoi des vues ? Est-ce le bon choix ? Pas toujours. C'est exactement ce qu'on regarde aujourd'hui avec la matérialisation, c'est-à-dire la façon dont dbt transforme un `SELECT` en objet réel dans Snowflake. Quatre options, un seul mot-clé pour passer de l'une à l'autre.

## C'est quoi une matérialisation

Quand on écrit un modèle dbt, on écrit juste un `SELECT`. La matérialisation, c'est la stratégie que dbt utilise pour stocker le résultat de ce `SELECT` dans Snowflake. Une vue ? Une table ? Quelque chose qui ne se reconstruit qu'en partie ?

dbt propose quatre matérialisations : **view**, **table**, **incremental** et **ephemeral**. Par défaut, c'est `view`. C'est pour ça que les trois modèles qu'on a créés sont des vues.

## View : le choix par défaut

Une vue, c'est une requête enregistrée. Elle ne stocke aucune donnée : à chaque fois qu'on l'interroge, Snowflake rejoue le `SELECT` derrière.

Les avantages :

- Construction quasi instantanée au `dbt run` (dbt crée juste un `CREATE VIEW`)
- Aucun stockage consommé
- Donnée toujours à jour, puisqu'elle est recalculée à la lecture

La limite et que si la requête est lourde (grosses jointures, agrégats sur des millions de lignes), elle est recalculée à chaque interrogation. Donc un dashboard qui tape dessus 200 fois par jour, c'est 200 fois le même calcul. Là, la vue devient un mauvais plan.

## Table : matérialiser pour aller vite à la lecture

Une table, c'est le résultat du `SELECT` figé physiquement dans Snowflake. dbt fait un `CREATE TABLE AS SELECT` et reconstruit la table entière à chaque `dbt run`.

Les avantages :

- Lecture rapide, le calcul a déjà été fait une fois
- Parfait pour les modèles métier interrogés souvent (les marts, ceux que l'outil BI consomme)

Le coût est du stockage, et surtout un recalcul complet à chaque `dbt run`. Si une table fait 500 millions de lignes et qu'on la reconstruit en entier tous les jours, la facture compute s'en souvient. Pour comprendre ce que coûte vraiment un recalcul, jette un oeil à [Query Profile](https://www.idriss-benbassou.com/query-profile-snowflake-performance-micro-partitions/).

## Comment changer la matérialisation

C'est là qu'arrive le fameux mot-clé. On ajoute un bloc `config` en haut du modèle. Ouvre ton mart `mart_clients_commandes.sql` et ajoute la première ligne :

```sql
{{ config(materialized='table') }}

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

```

```powershell
dbt run

```

Retourne dans Snowsight, déplie `ANALYTICS` \> `DEV`. Le `mart_clients_commandes` n'est plus une vue, c'est une table. Un seul mot-clé a tout changé, et on n'a pas touché au SQL.

![](https://storage.ghost.io/c/60/f1/60f18be4-df79-4956-8e4a-c2fa80212e93/content/images/2026/05/image-18.png)

## Ephemeral : du code réutilisable, sans objet en base

La troisième option est plus discrète. Un modèle `ephemeral` n'est pas matérialisé dans Snowflake. dbt ne crée ni vue ni table. À la place, il injecte le `SELECT` directement comme une CTE dans les modèles qui l'appellent avec `ref()`.

```sql
{{ config(materialized='ephemeral') }}

select
    customer_id,
    sum(montant) as total_depense
from {{ ref('stg_orders') }}
group by 1

```

Quand un autre modèle fait `ref()` sur celui-ci, dbt colle le code dedans au lieu de lire une table. C'est utile pour une logique intermédiaire courte, réutilisée à plusieurs endroits, mais qu'on ne veut pas exposer comme objet en base.

💡

Attention comme il n'existe pas dans Snowflake, on ne peut pas l'interroger directement ni le tester facilement. À réserver aux petites briques intermédiaires.

## Incremental : ne reconstruire que le nouveau

La quatrième est la plus puissante et la plus technique. Un modèle `incremental` construit la table une première fois, puis aux exécutions suivantes ne traite que les nouvelles lignes au lieu de tout reconstruire.

Pourquoi recalculer 2 ans d'historique chaque nuit alors que seules les données d'hier ont changé ? On gagne un temps et un coût de calcul énormes.

C'est aussi le sujet le plus dense, avec la fonction `is_incremental()`, la clé `unique_key` et les stratégies de mise à jour. On lui consacrera un article entier plus loin dans la série. Pour l'instant, retiens juste qu'elle existe et à quoi elle sert.

## Bonus Snowflake : la Dynamic Table

Les quatre matérialisations au-dessus existent sur tous les warehouses. Mais comme on est sur Snowflake on a accès à une cinquième, native et c'est la **Dynamic Table**.

L'idée est au lieu que dbt gère lui-même le delta (comme `incremental`), on déclare juste le `SELECT` et la fraîcheur cible, et [Snowflake s'occupe du refresh incrémental tout seul](https://www.idriss-benbassou.com/dynamic-table-snowflake-pipelines-chargement-incremental/).

Depuis dbt 1.12, c'est une matérialisation native. Tu l'actives comme les autres :

```sql
{{ config(
    materialized='dynamic_table',
    snowflake_warehouse='dbt_wh',
    target_lag='1 hour'
) }}

select
    customer_id,
    sum(montant) as total_depense,
    count(*)     as nb_commandes
from {{ ref('stg_orders') }}
group by 1
```

Deux réglages :

- `**target_lag**` : la fraîcheur maximale qu'on accepte. `'1 hour'` veut dire "ne jamais avoir plus d'une heure de retard sur la source". Snowflake décide alors tout seul quand rafraîchir pour tenir cet objectif. On peut aussi mettre `'downstream'` pour qu'elle ne se rafraîchisse que quand une table en aval en a besoin.
- **`snowflake_warehouse`** : le warehouse qui exécute les refreshs.

Le gros intérêt est que si rien n'a changé en amont depuis le dernier refresh, Snowflake saute le refresh et donc le coût compute est nul.

💡

Nb : Quand tu changes la requête, il faut faire un full reload `dbt run --full-refresh` (DROP/CREATE) et pour le refresh incrémental, les tables sources ont besoin d'avoir `CHANGE_TRACKING = TRUE`.

Pour plus d'infos sur les [dynamic table](https://www.idriss-benbassou.com/dynamic-table-snowflake-pipelines-chargement-incremental/) avec dbt voir [la doc ](https://docs.getdbt.com/reference/resource-configs/snowflake-configs?version=2.0&name=Fusion&ref=idriss-benbassou.com) 

## Quand choisir quoi

| Matérialisation | Ce que dbt fait                             | Quand l'utiliser                                 |
| --------------- | ------------------------------------------- | ------------------------------------------------ |
| view            | Crée une vue, rien n'est stocké             | Staging, modèles légers, donnée toujours fraîche |
| table           | Reconstruit une table complète à chaque run | Marts lus souvent, requêtes lourdes              |
| ephemeral       | Injecte le SQL en CTE, aucun objet créé     | Logique intermédiaire courte et réutilisée       |
| incremental     | Ne traite que les nouvelles lignes          | Grosses tables d'événements ou de logs           |

## Le pattern recommandé : configurer par dossier

Mettre `{{ config() }}` dans chaque modèle, ça marche, mais ça devient vite répétitif. La bonne pratique, c'est de définir la matérialisation par dossier, une fois pour toutes, dans le `dbt_project.yml`.

Ouvre-le et configure la section `models` comme ça :

```yaml
models:
  dbt_projet:
    staging:
      +materialized: view
    marts:
      +materialized: table

```

On vient de dire que "tout ce qui est dans `staging/` est une vue, tout ce qui est dans `marts/` est une table". On peut maintenant retirer le `{{ config(materialized='table') }}` du mart, il est couvert par la règle du dossier.

**Config au niveau modèle ou au niveau dossier ?**

💡

La règle du dossier dans `dbt_project.yml` fixe le défaut pour tous les modèles du dossier. Le `{{ config() }}` dans un modèle précis prend le dessus. Donc en pratique : on définit la stratégie générale par dossier, et on ne met un `config()` dans un modèle que pour l'exception. C'est plus propre et ça se lit facilement.

Cette logique colle au [Médaillon ](https://www.idriss-benbassou.com/architecture-medaillon-bronze-silver-gold-erreurs-a-eviter/)qu'on a vu avec le staging (Silver), les marts (Gold) deviennent des tables rapides à lire pour la BI et dataviz. Et pour comprendre ce que ces tables deviennent côté Snowflake, j'ai détaillé les [types de tables Snowflake](https://www.idriss-benbassou.com/types-tables-snowflake-permanent-transient-temporary-external/) dans la [formation Snowflake](https://www.idriss-benbassou.com/formation-snowflake/).

## La suite ?

Récap. de ce qu'on a vu dans cet article :

- Comprendre ce qu'est une matérialisation
- Voir les quatre stratégies : `view`, `table`, `ephemeral`, `incremental`
- Changer un modèle de vue en table avec un seul mot-clé
- Mettre en place la config par dossier dans `dbt_project.yml`

Les modèles sont maintenant matérialisés intelligemment selon leur rôle. Dans le prochain article, on s'assure qu'ils sont aussi fiables donc on attaque les tests dbt, pour vérifier automatiquement que la donnée n'est pas cassée (clés en double, valeurs nulles, références orphelines etc....)

---

## 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](https://www.idriss-benbassou.com/formation-dbt/)

dbt tourne sur Snowflake dans ce parcours. Pour maîtriser le socle (warehouses, rôles, ingestion) :

👉 [Accéder à la formation Snowflake](https://www.idriss-benbassou.com/formation-snowflake/)

Et pour t'entraîner sur dbt en conditions d'examen, la certification dbt Analytics Engineering teste précisément les matérialisations et leurs cas d'usage.

👉 [Préparer la certification dbt sur DataCertification.fr](https://datacertification.fr/certifications/dbt?ref=idriss-benbassou.com)

Tu veux que je t'accompagne sur ton projet data (Snowflake, dbt, modélisation, industrialisation) ?

👉 [Réserver un appel de 30 minutes](https://calendly.com/idriss-benbassou-datavio/30min?ref=idriss-benbassou.com)

---

## Questions fréquentes

#### Pourquoi les modèles dbt sont des vues par défaut ?

dbt crée juste une vue, sans stockage ni recalcul à la construction, et la donnée reste toujours à jour. C'est un bon défaut pour démarrer et pour les couches légères comme le staging. On passe à une table seulement quand la lecture devient trop lente.

#### Vue ou table en dbt, comment choisir ?

Une vue ne stocke rien et recalcule à chaque lecture donc idéale pour les modèles légers ou peu interrogés. Une table fige le résultat et se lit vite, mais se reconstruit en entier à chaque run et consomme du stockage.

#### C'est quoi une matérialisation ephemeral en dbt ?

Un modèle ephemeral n'est pas matérialisé dans Snowflake. dbt injecte son SQL directement comme une CTE dans les modèles qui l'appellent avec ref(). C'est utile pour une logique intermédiaire courte et réutilisée, mais comme il n'existe pas en base, on ne peut ni l'interroger ni le tester directement.

#### Où configure-t-on la matérialisation d'un modèle dbt ?

À deux endroits. Dans le modèle lui-même avec un bloc config, par exemple config(materialized='table'). Ou par dossier dans le dbt\_project.yml avec la clé +materialized, ce qui fixe le défaut pour tous les modèles du dossier. La config dans le modèle prend le dessus sur celle du dossier.

#### La matérialisation incremental, c'est pour quoi ?

Pour les grosses tables où reconstruire tout à chaque run serait trop coûteux. Un modèle incremental construit la table une fois, puis ne traite que les nouvelles lignes aux exécutions suivantes. C'est idéal pour les tables d'événements ou de logs, au prix d'une configuration un peu plus avancée avec is\_incremental() et une clé unique.

####