GUIDE TECHNIQUE DATA

Meltano : Le Guide Complet de l'ELT

Extraire, charger et orchestrer vos données avec le framework open-source de référence. Infrastructure as Code pour vos pipelines de données.

ELT Framework
15 min
GitOps

Qu'est-ce que Meltano ?

Meltano est un framework open-source pour les pipelines de données ELT (Extract-Load-Transform). Créé initialement par GitLab, puis devenu un projet indépendant, Meltano gère l'ensemble du cycle de vie de vos données : extraction depuis les sources, chargement dans un data warehouse, et orchestration du pipeline complet (incluant dbt pour les transformations).

E + L
Extraction et Chargement — le « EL » du ELT, complément naturel de dbt (le « T »)
600+
Connecteurs disponibles via le Hub Singer (APIs, bases de données, fichiers, SaaS)
100%
Open-source (licence MIT) — pas de vendor lock-in, pas de coûts cachés
CLI-first
Configuration as Code — tout est dans un fichier meltano.yml versionné dans git

Analogie pour débutants

Si dbt est le chef cuisinier qui transforme les ingrédients en plats, Meltano est le livreur qui va chercher les ingrédients chez les fournisseurs (APIs, bases de données, fichiers CSV) et les range dans le frigo (data warehouse). Meltano est aussi le manager du restaurant qui coordonne les livraisons et la cuisine pour que tout se passe dans le bon ordre, au bon moment.

Meltano vs Alternatives

Critère Meltano Fivetran Airbyte
Prix Gratuit (open-source) $$$$ (par ligne synchronisée) Freemium / payant cloud
Hébergement Self-hosted (vous) Fully managed (eux) Les deux
Connecteurs 600+ (Singer Hub) 300+ (propriétaires) 350+ (open-source)
Customisation ⭐⭐⭐ Totale ⭐ Limitée ⭐⭐ Bonne
Config as Code ✅ meltano.yml natif ❌ UI web ⚠️ Partiel (Octavia CLI)
Orchestration intégrée ✅ Airflow intégré ✅ Intégré ✅ Intégré
dbt intégré ✅ Natif ⚠️ dbt Cloud séparé ⚠️ Via Terraform
Vendor lock-in ❌ Aucun ⚠️ Fort ⚠️ Modéré (cloud)
Idéal pour Équipes techniques, startups, contrôle total Équipes non-techniques, enterprise Compromis technique/facilitée

Vision Globale : Meltano dans le Modern Data Stack

L'Architecture ELT Complète avec Meltano + dbt

Étape Outil Ce qui se passe
1. Extract Meltano (tap-*) Récupère les données depuis les APIs, BDD, fichiers
2. Load Meltano (target-*) Charge les données brutes dans le warehouse
3. Transform dbt (via Meltano) Transforme les données brutes en modèles analytiques
4. Orchestrate Meltano (Airflow) Planifie et exécute le pipeline automatiquement
5. Visualize Metabase / Looker / Evidence Crée des dashboards sur les marts dbt

Meltano + dbt = Le combo parfait

Meltano gère l'extraction et le chargement (EL), dbt gère la transformation (T). Ensemble, ils forment un pipeline ELT complet, 100% open-source, 100% configuration-as-code, et 100% reproductible. Meltano intègre dbt nativement : vous pouvez exécuter meltano run tap-postgres target-snowflake dbt-snowflake:run en une seule commande.

Concepts Clés de Meltano

1. Taps (Extracteurs)

Un tap est un connecteur qui extrait des données depuis une source. Il lit les données et les émet dans un format standardisé (Singer).

# Ajouter un tap pour extraire depuis PostgreSQL
$ meltano add extractor tap-postgres

# Ajouter un tap pour l'API GitHub
$ meltano add extractor tap-github

# Ajouter un tap pour des fichiers CSV
$ meltano add extractor tap-csv

2. Targets (Loaders / Chargeurs)

Un target est un connecteur qui charge les données dans une destination. Il reçoit le flux de données du tap et l'écrit dans le warehouse.

# Ajouter un target pour charger dans Snowflake
$ meltano add loader target-snowflake

# Charger dans PostgreSQL
$ meltano add loader target-postgres

# Charger dans des fichiers JSON (debug)
$ meltano add loader target-jsonl

3. Le fichier meltano.yml

C'est le cœur de votre projet Meltano. Toute la configuration est dans ce seul fichier YAML, versionné dans git :

# meltano.yml
version: 1
project_id: mon-projet-data

plugins:
  extractors:
    - name: tap-postgres
      variant: meltanolabs
      pip_url: meltanolabs-tap-postgres
      config:
        host: localhost
        port: 5432
        database: app_production
        user: readonly_user
      select:
        - public-orders.*    # Sélectionner toutes les colonnes
        - public-customers.* # de ces tables
        - "!public-logs.*"   # Exclure cette table

  loaders:
    - name: target-snowflake
      variant: meltanolabs
      pip_url: meltanolabs-target-snowflake
      config:
        account: xy12345.eu-west-1
        database: RAW
        schema: POSTGRES
        warehouse: LOADING_WH

  transformers:
    - name: dbt-snowflake
      pip_url: dbt-core dbt-snowflake

jobs:
  - name: daily-sync
    tasks:
      - tap-postgres target-snowflake dbt-snowflake:run

schedules:
  - name: daily-sync-schedule
    job: daily-sync
    interval: "@daily"

4. Environnements

Meltano supporte des environnements distincts (dev, staging, prod) avec des configurations différentes :

# meltano.yml
environments:
  - name: dev
    config:
      plugins:
        extractors:
          - name: tap-postgres
            config:
              host: localhost
              database: app_dev

  - name: prod
    config:
      plugins:
        extractors:
          - name: tap-postgres
            config:
              host: prod-db.company.com
              database: app_production

# Exécution :
$ meltano --environment=dev run tap-postgres target-snowflake
$ meltano --environment=prod run tap-postgres target-snowflake

5. State Management (Gestion d'État)

Meltano garde un état (state) entre chaque exécution pour ne récupérer que les nouvelles données (synchronisation incrémentale) :

Première exécution : récupère tout depuis le début.
Exécutions suivantes : récupère seulement les données créées/modifiées depuis la dernière exécution.
Cet état est stocké localement ou dans un backend configurable (base de données, S3, etc.).

Use Cases Activables

1. Synchroniser une Base de Données vers un Warehouse

PostgreSQL → Snowflake

# 1. Initialiser le projet
$ meltano init mon-pipeline && cd mon-pipeline

# 2. Ajouter les plugins
$ meltano add extractor tap-postgres
$ meltano add loader target-snowflake

# 3. Configurer (ou via meltano.yml)
$ meltano config tap-postgres set host db.company.com
$ meltano config tap-postgres set database production
$ meltano config tap-postgres set user readonly

# 4. Sélectionner les tables
$ meltano select tap-postgres "public-users" "*"
$ meltano select tap-postgres "public-orders" "*"
$ meltano select tap-postgres "public-payments" "*"

# 5. Lancer la synchronisation
$ meltano run tap-postgres target-snowflake

2. Extraire des Données depuis une API SaaS

GitHub → PostgreSQL

# Synchroniser les issues, PRs et commits
$ meltano add extractor tap-github
$ meltano config tap-github set repositories '["org/repo1", "org/repo2"]'
$ meltano config tap-github set auth_token $GITHUB_TOKEN
$ meltano select tap-github "issues" "*"
$ meltano select tap-github "pull_requests" "*"
$ meltano select tap-github "commits" "*"

$ meltano add loader target-postgres
$ meltano run tap-github target-postgres

3. Pipeline Complet E-Commerce (ELT)

Shopify + Stripe → Snowflake → dbt → Metabase

# meltano.yml - Jobs composés
jobs:
  - name: ecommerce-pipeline
    tasks:
      # Étape 1 : Extraire Shopify
      - tap-shopify target-snowflake
      # Étape 2 : Extraire Stripe
      - tap-stripe target-snowflake
      # Étape 3 : Transformer avec dbt
      - dbt-snowflake:run
      # Étape 4 : Tester avec dbt
      - dbt-snowflake:test

schedules:
  - name: ecommerce-daily
    job: ecommerce-pipeline
    interval: "@daily"  # Tous les jours à minuit

4. Centraliser les Logs d'Application

# Extraire depuis S3 + charger dans BigQuery
$ meltano add extractor tap-s3-csv
$ meltano config tap-s3-csv set bucket my-logs-bucket
$ meltano config tap-s3-csv set prefix "logs/2026/"

$ meltano add loader target-bigquery
$ meltano run tap-s3-csv target-bigquery

5. Migration de Base de Données

# MySQL production → PostgreSQL analytics
$ meltano add extractor tap-mysql
$ meltano add loader target-postgres

# Sync complet puis incrémental
$ meltano run tap-mysql target-postgres
# La 2e exécution ne prend que les deltas

6. Data Mesh : Extraction Multi-Sources

# meltano.yml — Pipeline multi-sources
jobs:
  - name: marketing-domain
    tasks:
      - tap-google-ads target-snowflake
      - tap-facebook target-snowflake
      - tap-hubspot target-snowflake
  - name: product-domain
    tasks:
      - tap-segment target-snowflake
      - tap-mixpanel target-snowflake
  - name: finance-domain
    tasks:
      - tap-stripe target-snowflake
      - tap-quickbooks target-snowflake

Cycle de Vie d'un Projet Meltano

Phase Commande Ce qui se passe
1. Init meltano init mon-projet Crée la structure de projet avec meltano.yml
2. Add Plugins meltano add extractor/loader Installe les connecteurs depuis le Hub Meltano
3. Configure meltano config Configure les credentials et options de chaque plugin
4. Select meltano select Choisit les tables/streams et colonnes à synchroniser
5. Test meltano run tap target Exécute le pipeline en dev pour valider
6. Schedule meltano schedule add Planifie l'exécution automatique (cron ou Airflow)
7. Deploy Docker / K8s / VM Déploie le projet avec orchestration en production
8. Monitor Logs + alertes Surveille les exécutions, détecte les échecs

Commandes Essentielles

# Initialiser un projet
meltano init mon-projet

# Lister les plugins disponibles
meltano discover extractors
meltano discover loaders

# Ajouter un plugin
meltano add extractor tap-postgres

# Configurer un plugin
meltano config tap-postgres set host localhost
meltano config tap-postgres list  # Voir la config

# Sélectionner des tables
meltano select tap-postgres --list --all  # Voir tout
meltano select tap-postgres "public-users" "*"

# Exécuter un pipeline
meltano run tap-postgres target-snowflake

# Exécuter avec dbt
meltano run tap-postgres target-snowflake dbt-snowflake:run

# Gérer l'état
meltano state list
meltano state get dev:tap-postgres-to-target-snowflake

# Orchestration
meltano schedule list
meltano invoke airflow scheduler

Features Clés

1. Sélection Fine des Données

# Sélectionner des tables spécifiques
$ meltano select tap-postgres "public-orders" "*"

# Exclure des colonnes sensibles
$ meltano select tap-postgres "public-users" "*"
$ meltano select tap-postgres "public-users" "!password"
$ meltano select tap-postgres "public-users" "!ssn"

# Utiliser des wildcards
$ meltano select tap-postgres "public-*" "*"  # Toutes les tables du schéma public

2. Gestion Sécurisée des Secrets

# Option 1 : Variables d'environnement
$ export TAP_POSTGRES_PASSWORD=my_secret
# Dans meltano.yml : password: $TAP_POSTGRES_PASSWORD

# Option 2 : Fichier .env (non versionné)
# .env
TAP_POSTGRES_PASSWORD=my_secret
TARGET_SNOWFLAKE_PASSWORD=another_secret

# Option 3 : Vault (avancé)
# Intégration avec HashiCorp Vault, AWS Secrets Manager, etc.

3. Orchestration avec Airflow

# Ajouter Airflow comme orchestrateur
$ meltano add orchestrator airflow

# Créer un schedule
$ meltano schedule add daily-sync \
    --job daily-pipeline \
    --interval "@daily"

# Démarrer le scheduler
$ meltano invoke airflow scheduler

# L'UI Airflow est accessible sur http://localhost:8080

4. Mappers (Transformation Légère)

Les mappers permettent des transformations entre le tap et le target (avant le chargement) :

# meltano.yml
plugins:
  mappers:
    - name: meltano-map-transformer
      variant: meltano
      pip_url: meltano-map-transformer
      mappings:
        - name: hash-emails
          config:
            stream_maps:
              users:
                email: null              # Supprimer le champ email
                email_domain: "record['email'].split('@')[1]"
                __else__: null           # Garder les autres champs

# Exécution avec le mapper
$ meltano run tap-postgres hash-emails target-snowflake

5. Replication Methods (Méthodes de Réplication)

Méthode Description Quand l'utiliser
FULL_TABLE Recharge la table entière à chaque run Petites tables de référence, pas de colonne updated_at
INCREMENTAL Ne charge que les lignes modifiées depuis le dernier run Tables volumineuses avec colonne updated_at fiable
LOG_BASED Utilise le WAL/binlog de la BDD pour le Change Data Capture Tables très volumineuses, besoin de temps réel

Le Protocole Singer & le SDK Meltano

Qu'est-ce que Singer ?

Singer est le protocole open-source sous-jacent utilisé par tous les connecteurs Meltano. C'est un standard simple : un tap émet des données en JSON sur stdout, un target les lit sur stdin. Ce découplage permet de combiner n'importe quel tap avec n'importe quel target.

Message Singer Rôle Exemple
SCHEMA Déclare la structure d'un stream {"type": "SCHEMA", "stream": "users", "schema": {...}}
RECORD Émet une ligne de données {"type": "RECORD", "stream": "users", "record": {"id": 1, "name": "Alice"}}
STATE Sauvegarde le point de reprise {"type": "STATE", "value": {"bookmarks": {"users": {"last_id": 42}}}}

Créer un Tap Custom avec le SDK Meltano

Si votre source n'a pas de connecteur existant, le Meltano Singer SDK facilite la création :

# 1. Créer le squelette du tap
$ pip install cookiecutter
$ cookiecutter https://github.com/meltano/sdk \
    --directory="cookiecutter/tap-template"

# 2. Implémenter le stream
# tap_myapi/streams.py
from singer_sdk import typing as th
from singer_sdk.streams import RESTStream

class UsersStream(RESTStream):
    name = "users"
    path = "/api/v1/users"
    primary_keys = ["id"]
    replication_key = "updated_at"

    schema = th.PropertiesList(
        th.Property("id", th.IntegerType),
        th.Property("name", th.StringType),
        th.Property("email", th.StringType),
        th.Property("updated_at", th.DateTimeType),
    ).to_dict()

    def get_url_params(self, context, next_page_token):
        params = {"page_size": 100}
        if next_page_token:
            params["page"] = next_page_token
        return params

Le Hub Meltano

Le Meltano Hub (hub.meltano.com) est le catalogue central de tous les connecteurs disponibles. Chaque connecteur a :

Les Grands Patterns Meltano

1. Pattern « One Source, One Pipeline »

Chaque source de données a son propre pipeline dédié (tap → target). Avantages :

2. Pattern « EL then T »

Séparer clairement l'extraction/chargement (Meltano) de la transformation (dbt). Ne jamais transformer pendant le chargement sauf pour des opérations triviales (hashing PII via mappers).

3. Pattern « Raw → Staging → Marts »

# Architecture des schémas dans le warehouse
RAW.SHOPIFY      ← Meltano charge ici (données brutes)
RAW.STRIPE       ← Meltano charge ici
ANALYTICS.STG    ← dbt staging (nettoyage)
ANALYTICS.INT    ← dbt intermediate (logique)
ANALYTICS.MARTS  ← dbt marts (tables finales)

4. Pattern « Full Refresh Weekly + Incremental Daily »

# meltano.yml - Deux schedules
schedules:
  - name: daily-incremental
    job: daily-sync        # Incrémental
    interval: "@daily"
  - name: weekly-full
    job: full-refresh      # Full table
    interval: "0 2 * * 0"  # Dimanche 2h

jobs:
  - name: full-refresh
    tasks:
      - tap-postgres target-snowflake --full-refresh

L'incrémental quotidien est rapide mais peut accumuler des dérives. Le full refresh hebdomadaire corrige les écarts.

5. Pattern « Hub and Spoke »

Pour les grandes organisations avec plusieurs domaines data :

Best Practices

1
Tout dans meltano.yml + git
Le fichier meltano.yml est votre source de vérité. Versionnez-le, reviewez les changements en PR, documentez les ajouts.
2
Secrets dans .env, JAMAIS dans meltano.yml
Utilisez des variables d'environnement pour les mots de passe et tokens. Le .env est dans le .gitignore.
3
Sélectionnez uniquement ce dont vous avez besoin
Ne synchronisez pas toutes les tables de votre BDD source. Sélectionnez les tables et colonnes utiles.
4
Testez en dev avant prod
Utilisez les environnements Meltano pour tester avec des données réduites avant de synchroniser en production.
5
Incrémental par défaut
Configurez la réplication incrémentale dès que possible. Le full refresh sur des tables de millions de lignes coûte cher.
6
Monitoring & Alertes
Configurez des alertes pour les pipelines qui échouent. Slack, PagerDuty, ou email — mais soyez alerté.
7
Isolez les pipelines
Un job par source. Si le tap-shopify échoue, le tap-stripe doit continuer à fonctionner.
8
Documentez le mapping des données
Pour chaque source, documentez quelles tables sont synchronisées, à quelle fréquence, et avec quelle méthode de réplication.

Anti-Patterns à Éviter

« Synchroniser tout »

Extraire toutes les tables de la BDD source « au cas où ». Résultat : des coûts warehouse élevés, des pipelines lents, et des données inutiles qui polluent le warehouse.

« Credentials en dur »

Mettre les mots de passe et tokens directement dans meltano.yml et les committer dans git. Utilisez toujours des variables d'environnement ou un gestionnaire de secrets.

« Transformer pendant le Load »

Utiliser les mappers pour faire des transformations métier complexes. Les mappers sont pour le masquage PII et le renommage basique. La vraie logique métier appartient à dbt.

« Full refresh quotidien sur des grandes tables »

Recharger 100 millions de lignes chaque jour alors que seules 10 000 ont changé. Utilisez la réplication incrémentale (INCREMENTAL ou LOG_BASED).

« Ignorer les erreurs de pipeline »

Pas de monitoring, pas d'alertes. Vos données sont stale depuis 3 jours et personne ne le sait. Le CEO prend des décisions sur des données obsolètes.

« Un seul mega-job »

Un job qui fait tap-a + tap-b + tap-c + target + dbt en séquence. Si tap-b échoue, tout s'arrête. Isolez les sources en jobs séparés.

Les Grandes Questions de Design

1. Meltano vs Fivetran vs Airbyte — Lequel choisir ?

  • Choisissez Meltano si : vous voulez le contrôle total, vous êtes à l'aise avec le CLI et le code, vous voulez éviter le vendor lock-in, et votre budget est limité.
  • Choisissez Fivetran si : vous ne voulez rien gérer, votre équipe est non-technique, et le budget n'est pas un problème.
  • Choisissez Airbyte si : vous voulez un compromis entre open-source et facilité d'utilisation, avec une UI web pour la configuration.

2. Comment choisir un variant de connecteur ?

3. Comment déployer en production ?

Méthode Complexité Idéal pour
Docker + Cron ⭐ Faible Petites équipes, projets simples
Docker + Airflow ⭐⭐ Moyenne Pipelines multiples avec dépendances
Kubernetes + Airflow ⭐⭐⭐ Élevée Grandes équipes, haute disponibilité
GitHub Actions + cron ⭐ Faible Projets personnels, POCs

4. Incremental vs Full Refresh vs CDC ?

Critère Full Refresh Incremental CDC (Log-Based)
Complexité ⭐ Simple ⭐⭐ Moyenne ⭐⭐⭐ Élevée
Vitesse Lente (tout recharger) Rapide (deltas seulement) Temps réel
Coût warehouse Élevé Faible Très faible
Captures les deletes ✅ Oui ❌ Non ✅ Oui
Prérequis source Aucun Colonne updated_at Access au WAL/binlog

5. Comment gérer la scalabilité ?

  • Paralléliser les pipelines : exécuter tap-shopify et tap-stripe en parallèle (pas en séquence)
  • Utiliser des workers Airflow : distribuer l'exécution sur plusieurs machines
  • Optimiser la sélection : ne synchroniser que les tables/colonnes nécessaires
  • Partitionner les grands extracts : utiliser des plages de dates pour les tables volumineuses

Quand Utiliser Quoi ?

Meltano
Contrôle total, CLI-first, config-as-code. Pour les équipes techniques qui veulent posséder leur pipeline.
Fivetran
Zéro maintenance, UI simple. Pour les équipes business qui veulent « just plug and play ».
Airbyte
Open-source + UI web. Le compromis entre Meltano (technique) et Fivetran (facilité).
Custom Python
Quand aucun connecteur n'existe et que le Singer SDK est trop lourd. Rare mais parfois nécessaire.

Pour démarrer avec Meltano

  1. pip install meltano
  2. meltano init mon-premier-pipeline
  3. meltano add extractor tap-csv (le plus simple pour commencer)
  4. meltano add loader target-jsonl (pour voir les données en sortie)
  5. Créez un fichier CSV de test et lancez meltano run tap-csv target-jsonl
  6. Puis passez à un vrai tap (PostgreSQL, API) et un vrai target (Snowflake, BigQuery)
Vision Globale : Mel…Concepts Clés de Mel…Use Cases ActivablesCycle de Vie d'un Pr…Features ClésLe Protocole Singer…Les Grands Patterns…Best PracticesAnti-Patterns à Évit…Les Grandes Question…Quand Utiliser Quoi…