dbt: Custom materializations

Créer une custom materialization dans dbt : guide complet avec exemple

Dans dbt, les materializations déterminent comment un modèle est transformé en objet physique dans le data warehouse (par exemple une table ou une vue). Par défaut, dbt fournit plusieurs materializations comme view, table, incremental ou ephemeral. Mais dans certains cas avancés, il est utile de définir une materialization personnalisée (custom materialization) afin d’adapter le comportement à des besoins spécifiques.

Cet article vous explique comment créer une custom materialization avec un exemple complet.


🔍 Pourquoi créer une custom materialization ?

Voici quelques cas d’usage :

  • Gérer une stratégie d’insertion personnalisée (par exemple : supprimer les anciennes lignes avant d’insérer les nouvelles)
  • Ajouter des hooks de logging ou d’audit
  • Implémenter une logique conditionnelle (par exemple : faire un full refresh tous les lundis)
  • Intégrer des spécificités d’un data warehouse

📂 Structure de base d’une custom materialization

Les materializations sont des macros déclarées dans macros/materializations/<nom>.sql. Une materialization doit :

  1. Utiliser le décorateur {% materialization nom, default %}
  2. Utiliser le contexte adapter.get_relation / adapter.drop_relation pour interagir avec le warehouse
  3. Retourner l’objet rel représentant la table créée ou modifiée

🌐 Exemple : materialization safe_overwrite

Ce comportement permet de :

  • Supprimer la table cible uniquement si elle existe
  • Ensuite créer une nouvelle table via une requête

1. Fichier macros/materializations/safe_overwrite.sql

{% materialization safe_overwrite, default %}
  {%- set identifier = model['alias'] -%}
  {%- set target_relation = api.Relation.create(
        database=target.database,
        schema=target.schema,
        identifier=identifier) -%}

  {% do log("[safe_overwrite] dropping existing table if exists", info=True) %}
  {% do adapter.drop_relation(target_relation) %}

  {% do log("[safe_overwrite] creating new table", info=True) %}
  {% set sql = materialization_default_sql(model) %}
  {% do run_query(sql) %}

  {{ return({'relations': [target_relation]}) }}
{% endmaterialization %}

2. Utilisation dans un modèle

-- models/fact/fact_ventes.sql
{{ config(materialized='safe_overwrite') }}

select * from {{ ref('stg_ventes') }}

📊 Astuces et bonnes pratiques

  • ✅ Tu peux utiliser is_incremental() si tu veux un comportement mixte initial/incrémental
  • ✅ Tu peux ajouter des pre_hook / post_hook dans la macro config() pour faire du logging, de l’audit ou de la notification
  • ✅ Pense à documenter les configs attendues dans la macro si tu ajoutes des options personnalisées (ex : unique_key, mode, etc.)

🧰 Conclusion

Les custom materializations te permettent d’étendre dbt et de l’adapter à tes contraintes techniques et métiers. Elles offrent un haut niveau de contrôle tout en bénéficiant de l’infrastructure de compilation, d’execution et de documentation de dbt.

N’oublie pas : ce sont de simples macros Jinja, donc tu peux loger, configurer, conditionner tout ce que tu veux, de façon testable et maintenable !

Leave a Reply

Your email address will not be published. Required fields are marked *