La facture de licence dbt Cloud arrive et quelqu’un dans l’équipe pose la question : « On ne pourrait pas simplement utiliser Dataform ? C’est gratuit. »
À 100 $/utilisateur/mois, une équipe analytics de 10 personnes paie 12 000 $ par an pour dbt Cloud. Dataform offre des capacités de transformation comparables à coût de licence nul pour les utilisateurs BigQuery. Le calcul semble convaincant. Mais les décisions de migration méritent un examen plus approfondi qu’une simple comparaison de coûts.
Ce guide couvre le processus de migration pour les projets dbt simples et complexes, établit la correspondance entre les concepts des deux outils et détaille quand la migration a du sens (et quand elle n’en a pas).
Pourquoi les équipes envisagent de migrer de dbt vers Dataform
Trois facteurs alimentent généralement les discussions sur la migration :
Les coûts de licence. Les 100 $/utilisateur/mois de dbt Cloud s’accumulent vite. Les équipes qui paient pour des fonctionnalités qu’elles n’utilisent pas pleinement (comme la couche sémantique ou le CI avancé) ressentent la pression le plus fortement. dbt Core reste gratuit, mais vous perdez les améliorations de vitesse de compilation de dbt Fusion et les fonctionnalités CI/CD natives.
La consolidation GCP. Dataform vit à l’intérieur de la console BigQuery. Pour les équipes déjà engagées dans GCP, avoir les transformations gérées aux côtés du warehouse simplifie les opérations. L’intégration native IAM, les métadonnées Dataplex et l’orchestration Cloud Composer créent une stack cohérente.
Le tournant de 2025. La fusion dbt-Fivetran annoncée en octobre 2025 signale une consolidation du secteur. Certaines équipes s’inquiètent de changements tarifaires ou de pivots stratégiques. Pendant ce temps, Google continue d’investir régulièrement dans Dataform : pas de développement de fonctionnalités agressif, mais une maintenance fiable et des certifications de conformité (SOC 1/2/3, HIPAA, ISO 27001).
Aucun de ces facteurs seul ne justifie une migration. La question est de savoir si votre situation spécifique fait pencher la balance.
Avant de commencer : le test de réalité de la migration
Les délais de migration varient considérablement selon la complexité du projet :
| Profil du projet | Délai | Répartition de l’effort |
|---|---|---|
| Petit (~20 modèles, pas de macros custom) | 1-2 semaines | 80 % automatisé, 20 % validation |
| Moyen (~50-100 modèles, quelques macros) | 2-4 semaines | 60 % automatisé, 40 % conversion de macros |
| Grand (100+ modèles, usage intensif de macros) | 2-3 mois | Réécriture manuelle de la logique programmatique |
| Entreprise (packages, pipelines ML) | 3-6 mois | Exécution parallèle, validation par les parties prenantes |
Ce que vous allez perdre
Avant de vous engager dans la migration, comprenez les lacunes de l’écosystème :
- Écosystème de packages : dbt dispose de 200+ packages sur hub.getdbt.com. Dataform n’a pas de hub de packages centralisé.
- Profondeur des tests : dbt_expectations fournit 50+ tests. Les assertions intégrées de Dataform couvrent l’unicité, les valeurs nulles et les conditions sur les lignes. C’est tout.
- Maturité CI/CD : dbt Cloud offre le Slim CI en quelques clics. Dataform nécessite une configuration manuelle avec Cloud Build ou GitHub Actions.
- Outillage éditeur : L’extension dbt Power User compte plus d’1M d’installations. Il n’existe pas d’extension Dataform comparable pour Cursor ou VS Code.
- Valeur sur le marché de l’emploi : Les compétences dbt apparaissent dans la plupart des offres d’emploi analytics engineer. L’expertise Dataform reste de niche.
Si ces pertes sont significatives pour votre équipe, la migration pourrait coûter plus qu’elle ne rapporte.
Correspondance des concepts dbt vers Dataform
Les concepts fondamentaux se transposent, mais la syntaxe diffère substantiellement.
Syntaxe de référence
dbt :
SELECT customer_id, customer__name, customer__email, customer__statusFROM {{ ref('base__source__customers') }}WHERE customer__status IN {{ var('active_statuses') }}Dataform :
SELECT customer_id, customer__name, customer__email, customer__statusFROM ${ref("base__source__customers")}WHERE customer__status IN ${dataform.projectConfig.vars.active_statuses}Modèles incrémentaux
dbt :
{{ config(materialized='incremental', unique_key='order_id') }}
SELECT order_id, customer_id, order__total_usd, order__created_at, order__updated_atFROM {{ ref('base__source__orders') }}{% if is_incremental() %} WHERE order__updated_at > (SELECT MAX(order__updated_at) FROM {{ this }}){% endif %}Dataform :
config { type: "incremental", uniqueKey: ["order_id"]}
SELECT order_id, customer_id, order__total_usd, order__created_at, order__updated_atFROM ${ref("base__source__orders")}${when(incremental(), `WHERE order__updated_at > (SELECT MAX(order__updated_at) FROM ${self()})`)}Tests de schéma vs assertions
dbt (schema.yml) :
models: - name: mrt__marketing__customers columns: - name: customer_id tests: [unique, not_null] - name: customer__email tests: - not_null - uniqueDataform (inline) :
config { type: "table", assertions: { uniqueKey: ["customer_id"], nonNull: ["customer_id", "customer__email"] }}Référence de complexité de conversion
| Fonctionnalité dbt | Équivalent Dataform | Complexité |
|---|---|---|
{{ ref('model') }} | ${ref('table')} | Faible (automatisé) |
{{ source('schema','table') }} | Fichiers de déclaration | Moyenne |
| Macros Jinja | Includes JavaScript | Élevée (manuelle) |
| Tests YAML de schéma | Assertions inline | Moyenne |
is_incremental() | when(incremental(), ...) | Faible |
| Seeds (fichiers CSV) | Tables BigQuery + déclarations | Moyenne |
| Snapshots (SCD2) | Implémentation manuelle | Élevée |
| Packages dbt | Pas d’équivalent | Lacune critique |
Les fonctionnalités qui ne se transposent pas
Certaines capacités de dbt nécessitent un travail significatif de réécriture ou n’ont pas d’équivalent dans Dataform.
Snapshots
Les snapshots dbt implémentent automatiquement les dimensions à évolution lente de type 2 (SCD Type 2). Dataform n’a pas de fonctionnalité de snapshot intégrée. Vous devrez implémenter manuellement les dimensions à évolution lente en utilisant des tables incrémentales avec une logique de merge personnalisée.
Packages dbt
Si votre projet utilise dbt_utils, dbt_expectations ou dbt_date, attendez-vous à une conversion manuelle. Les fonctions courantes de [[fr/guide-macros-dbt|dbt_utils]] comme surrogate_key ou star nécessitent des équivalents JavaScript ou du SQL inline. L’outil de migration gère certaines fonctions dbt_utils, mais la couverture est incomplète.
Stratégie incrémentale microbatch
Le traitement microbatch de dbt, introduit en 2024, n’a pas d’équivalent dans Dataform. Si vous traitez des données par lots temporels pour des raisons de performance ou de maîtrise des coûts, vous devrez restructurer votre approche.
Slim CI
Le Slim CI de dbt Cloud ne build que les modèles modifiés plus leurs dépendants, en créant automatiquement des schémas PR. Reproduire cela dans Dataform nécessite d’appeler l’API REST Dataform depuis des outils CI externes. C’est possible, mais demande nettement plus de configuration.
Processus de migration étape par étape
1. Auditer votre projet
Avant de toucher au code, inventoriez ce que vous avez :
# Compter les modèles par typefind models -name "*.sql" | wc -l
# Lister les fichiers de macrosfind macros -name "*.sql"
# Vérifier packages.yml pour les dépendancescat packages.ymlDocumentez :
- Le nombre total de modèles
- Le nombre de macros personnalisées
- Les packages externes utilisés
- Les stratégies de modèles incrémentaux
- Les tables snapshot
- La complexité CI/CD
2. Exécuter l’outil de migration automatisé
L’outil ra_dbt_to_dataform gère la conversion de base :
# Cloner l'outil de migrationgit clone https://github.com/rittmananalytics/ra_dbt_to_dataform.gitcd ra_dbt_to_dataform
# Installer les dépendancespip install -r requirements.txt
# Lancer la migration (utilise GPT-4 pour la conversion de macros complexes)python migrate.py --dbt-project /path/to/dbt --output /path/to/dataformL’outil convertit :
- Les références de modèles (syntaxe
ref()) - Les déclarations de sources
- Les fonctions courantes de
dbt_utils - La logique incrémentale de base
Il ne gère pas :
- Les seeds
- Les snapshots
- Les macros personnalisées complexes
- Les définitions de la couche sémantique
3. Convertir les macros en includes JavaScript
Dataform utilise des fichiers JavaScript pour la logique réutilisable. Créez un répertoire includes/ pour les fonctions partagées.
Macro dbt (generate_surrogate_key.sql) :
{% macro generate_surrogate_key(field_list) %} TO_HEX(MD5(CONCAT({% for field in field_list %}COALESCE(CAST({{ field }} AS STRING), ''){% if not loop.last %}, '|', {% endif %}{% endfor %}))){% endmacro %}JavaScript Dataform (includes/utils.js) :
function generateSurrogateKey(fields) { const fieldExpressions = fields .map(f => `COALESCE(CAST(${f} AS STRING), '')`) .join(", '|', "); return `TO_HEX(MD5(CONCAT(${fieldExpressions})))`;}
module.exports = { generateSurrogateKey };Utilisation en SQLX :
config { type: "table" }
js { const { generateSurrogateKey } = require("includes/utils");}
SELECT ${generateSurrogateKey(["customer_id", "order__created_at"])} AS surrogate_key, customer_id, order__created_at, order__total_usdFROM ${ref("base__source__orders")}4. Recréer les tests sous forme d’assertions
Les assertions intégrées de Dataform couvrent les cas de base :
config { type: "table", assertions: { uniqueKey: ["order_id"], nonNull: ["order_id", "customer_id", "order__created_at"], rowConditions: [ "order__total_usd >= 0", "order__created_at <= CURRENT_DATE()" ] }}Pour les validations complexes, créez des fichiers d’assertion séparés :
-- definitions/assertions/assert_valid_customer_emails.sqlxconfig { type: "assertion" }
SELECT customer_id, customer__emailFROM ${ref("mrt__marketing__customers")}WHERE customer__email NOT LIKE '%@%.%' OR customer__email IS NULLLes tests de dbt_expectations comme les vérifications de distribution, les patterns regex ou les comparaisons inter-tables nécessitent des fichiers d’assertion personnalisés.
5. Mettre en place l’orchestration
Les workflows Dataform ne se déclenchent pas nativement à partir d’événements git. Choisissez une approche d’orchestration :
Cloud Composer (Airflow managé) :
from airflow.providers.google.cloud.operators.dataform import ( DataformCreateCompilationResultOperator, DataformCreateWorkflowInvocationOperator,)
compile_task = DataformCreateCompilationResultOperator( task_id="compile", project_id="my-project", region="us-central1", repository_id="my-repo",)
run_task = DataformCreateWorkflowInvocationOperator( task_id="run", project_id="my-project", region="us-central1", repository_id="my-repo", compilation_result="{{ task_instance.xcom_pull('compile') }}",)Cloud Scheduler + Workflows :
main: steps: - compile: call: http.post args: url: https://dataform.googleapis.com/v1beta1/projects/PROJECT/locations/REGION/repositories/REPO/compilationResults auth: type: OAuth2 - run: call: http.post args: url: https://dataform.googleapis.com/v1beta1/projects/PROJECT/locations/REGION/repositories/REPO/workflowInvocations6. Exécution parallèle et validation
Ne basculez pas immédiatement. Exécutez les deux pipelines simultanément :
- Déployez le projet Dataform dans un dataset séparé (par ex.
analytics_dataform) - Planifiez dbt et Dataform pour s’exécuter à la même cadence
- Comparez les résultats avec des comptages de lignes et des checksums
- Validez les dashboards en aval par rapport aux deux sources
- Surveillez pendant 2 à 4 semaines avant de décommissionner dbt
-- Requête de validationSELECT 'dbt' AS source, COUNT(*) AS row_count, FARM_FINGERPRINT(TO_JSON_STRING(ARRAY_AGG(t ORDER BY order_id))) AS checksumFROM `analytics.mrt__sales__orders` tUNION ALLSELECT 'dataform' AS source, COUNT(*) AS row_count, FARM_FINGERPRINT(TO_JSON_STRING(ARRAY_AGG(t ORDER BY order_id))) AS checksumFROM `analytics_dataform.mrt__sales__orders` tQuand la migration n’a pas de sens
La migration n’est pas toujours le bon choix. Reconsidérez sérieusement si :
Vous dépendez fortement des packages dbt. Convertir dbt_utils, dbt_expectations ou des packages spécialisés comme dbt-ga4 demande un effort considérable. Si les packages apportent une valeur significative, cette valeur disparaît après la migration.
Le multi-warehouse est dans la feuille de route. Dataform ne supporte que BigQuery. S’il y a la moindre chance que vous ajoutiez Snowflake, Databricks ou un autre warehouse dans les 2 à 3 prochaines années, l’écosystème d’adaptateurs dbt prend de la valeur.
Le développement de carrière de l’équipe compte. Les compétences dbt sont quasi universelles dans les offres d’emploi analytics engineer. L’expertise Dataform est de niche. Si votre équipe valorise la portabilité de carrière, l’expérience dbt la sert mieux.
Vous utilisez des stratégies incrémentales complexes. Le traitement microbatch, la logique de merge sophistiquée ou les patterns de données en retard sont plus faciles à gérer dans dbt. Le support incrémental de Dataform est basique.
Le coût de migration dépasse les économies de licence. Une migration de 2-3 mois pour un ingénieur senior coûte entre 30 000 et 50 000 $ en salaire seul. Ajoutez le débogage, la validation et les corrections en aval. Comparez aux 12 000 $/an de licence. Si la migration met plus de 2 ans à être rentabilisée, reconsidérez.
Prendre la décision
Utilisez ce cadre pour évaluer votre situation :
Migrer vers Dataform quand :
- Engagement 100 % BigQuery sans plans multi-cloud
- Moins de 50 modèles avec un minimum de macros personnalisées
- Pas de dépendance aux packages dbt au-delà des basiques de dbt_utils
- Pression sur les coûts aiguë (startup, budget contraint)
- L’équipe préfère JavaScript à Jinja
- L’intégration GCP compte plus que la largeur de l’écosystème
Rester avec dbt quand :
- Utilisation active des fonctionnalités dbt Cloud (couche sémantique, Mesh, CI avancé)
- Usage intensif de macros rendant la conversion douloureuse
- Les pipelines ML dépendent d’un comportement de templating spécifique
- L’équipe grandit et a besoin d’un levier de recrutement
- Une stratégie multi-warehouse est envisageable
- Le retour sur investissement de la migration dépasse 2 ans
La question honnête
Posez-vous une seule question : votre organisation est-elle BigQuery pour toujours ?
Si oui (sincèrement, stratégiquement, pour l’avenir prévisible), Dataform offre un chemin crédible pour éliminer les coûts de licence. L’outil est mature, l’investissement de Google est constant, et l’intégration BigQuery est excellente.
S’il y a de l’incertitude, la flexibilité de dbt a une valeur d’option. Le coût de licence vaut peut-être la peine d’être payé pour la capacité de changer de cap ultérieurement.
Aucune des deux réponses n’est mauvaise. L’erreur est de migrer uniquement pour les économies de coûts sans tenir compte des compromis d’écosystème et de l’effort de conversion. Faites les calculs avec des délais réalistes, pas optimistes.