Pipeline to Dashboardnihalsulaiman.com

Week 7 · Run it in production › Day 45

Day 45. Choosing tools with a written rationale

⏱ 4h · learn 80m · lab 125m · ship 20m · review 15m🏷 allBefore: Day 44

By the end of today you can

  • Compare orchestrators (Dagster, Airflow, Prefect, Mage, Kestra, Data Factory) on criteria that matter
  • Compare ingestion tools (dlt, Airbyte, Meltano, managed connectors) and transformation tools (dbt, SQLMesh)
  • Port one pipeline to a second orchestrator and report what changed
  • Write a weighted decision matrix and an ADR

1. Why this matters

Job ads list different tools: Airflow here, ADF there, Prefect somewhere else. You can't master all of them in 7 weeks, but you can understand the shared concepts (Weeks 1–6) and how each tool expresses them. That's what lets a senior person switch tools in a week.

2. Orchestrators

Dagster Airflow Prefect Mage Kestra Azure Data Factory / Fabric
Model Assets (data-first) Tasks/DAGs (assets added in v3) Python flows/tasks Blocks in a notebook-like UI YAML flows, event-driven Low-code pipelines
Local dev & tests Excellent Improved; heavier Very easy Easy Easy (Docker) Portal-based
Partitions/backfills First-class Good (data intervals) Manual patterns Basic Good Tumbling windows
Lineage Built-in, column-level with dbt Via OpenLineage Limited Basic Basic Via Purview
Ecosystem Growing, strong dbt/dlt Largest (providers) Good Smaller Growing Azure-native connectors
Hosting OSS or Dagster+ OSS, MWAA, Astronomer, Cloud Composer OSS server or Prefect Cloud OSS or Pro OSS or Enterprise Pay per activity

Airflow skills are still the most requested in ads; Dagster is increasingly common in modern stacks; ADF is everywhere in Microsoft enterprises.

The same pipeline in Airflow (TaskFlow API)

from airflow.sdk import dag, task          # Airflow 3; in Airflow 2: from airflow.decorators import dag, task
import pendulum

@dag(schedule="15 6 * * *", start_date=pendulum.datetime(2026, 9, 1, tz="America/Toronto"), catchup=True)
def hotel_daily():
    @task(retries=3)
    def land(ds=None):           # ds = logical date as YYYY-MM-DD, the "business date" for this run
        return pms.land_day(ds)
    @task
    def stage(path: str):
        return pms.stage(path)
    stage(land())
hotel_daily()

And in Prefect

from prefect import flow, task
@task(retries=3, retry_delay_seconds=30)
def land(bdate: str) -> str: return pms.land_day(bdate)
@flow
def hotel_daily(bdate: str): pms.stage(land(bdate))

Notice your pms core module didn't change. That's the payoff of the Day 15 rule.

3. Ingestion tools

  • dlt: Python library, code-first, runs inside any orchestrator, cheap. Great for APIs and files.
  • Airbyte: hundreds of connectors with a UI; self-host (needs a bit of infrastructure) or cloud.
  • Meltano: Singer taps/targets with CLI and config, OSS.
  • Fivetran / Azure Data Factory copy / Fabric: managed connectors, priced per volume/activity; the fastest start, the highest bill at scale.

4. Transformation

dbt (Core is open source; dbt Cloud adds hosted IDE/scheduling) is the default. SQLMesh is the strongest alternative, with virtual environments and plan/apply. Stored procedures remain common in SQL Server shops.

Maths and principle

Principle: a weighted decision matrix makes trade-offs explicit and arguable.

Equation: score\(_j = \sum_i w_i s_{ij}\) with \(\sum w_i = 1\), scores \(s_{ij} \in [1, 5]\). Run a sensitivity check: does the winner change if any single weight moves by ±0.1? If yes, the decision is close and depends on that criterion; say so.

Analogy: a weighted least-squares fit: weights encode how much you trust each measurement. Where it breaks: double-counting correlated criteria ("easy to learn" and "fast onboarding") inflates them. Merge them.

Try it: weights cost 0.4, skills fit 0.4, features 0.2. Tool A scores 3, 5, 4; Tool B scores 5, 2, 5. Winner? (A: 1.2 + 2.0 + 0.8 = 4.0; B: 2.0 + 0.8 + 1.0 = 3.8 → A, narrowly.)

The 5-year lens

Interviewers ask "why Dagster and not Airflow?" to see if you can argue both sides. A good answer: "Dagster's asset model, partitions and local testing suited a small team building a new platform. In a company with 300 existing Airflow DAGs and an Airflow-skilled team, I'd stay on Airflow 3, adopt its asset features and OpenLineage, and keep business logic in plain Python and dbt so the orchestrator stays swappable."

Lab

  1. Port the hotel pipeline (land → stage → OTB) to Airflow (Astro CLI or the official Docker Compose) or Prefect (pip install prefect; prefect server start). Keep the core module unchanged.
  2. Run a backfill in that tool. Note how partitions/intervals work there compared with Dagster.
  3. Re-implement the ads ingest with dlt and, if your machine allows, try Airbyte OSS with its Postgres destination.
  4. Build a weighted decision matrix for three company profiles (40-store Microsoft retail chain; 300-restaurant Google Workspace QSR; 5-hotel group with no IT team). Do the sensitivity check.
  5. Write ADR-002 (orchestrator) and ADR-003 (ingestion) for the capstone.

Ship

docs+feat: Airflow/Prefect port, dlt/Airbyte trial, decision matrices, ADR-002/003.

Check yourself

1. You ported a pipeline from Dagster to Prefect and only changed the orchestration file. What made that possible?

2. A company has 300 Airflow DAGs and an Airflow-skilled team. Best recommendation?

3. In a sensitivity check, the winner flips when one weight changes by 0.1. What do you report?

My notes