Airflow
Airflow is an orchestrator: it decides when tasks should run, in what dependency order, with what retries and metadata. It does not make bad SQL correct or turn an unreliable source into a contract; it gives data-pipelines a schedulable control plane.
A minimal DAG
Airflow represents a workflow as a directed acyclic graph. The artifact below is a minimal DAG shape for an ELT pipeline: one task extracts a dated object, one task runs dbt, and one task blocks publication unless a data-quality check passes.
from __future__ import annotations
import pendulum
from airflow.decorators import dag, task
@dag(
dag_id="orders_daily_mart",
schedule="0 5 * * *",
start_date=pendulum.datetime(2026, 1, 1, tz="UTC"),
catchup=True,
max_active_runs=1,
tags=["orders", "warehouse"],
)
def orders_daily_mart():
@task
def extract(ds: str) -> str:
return f"gs://raw/orders/dt={ds}/orders.jsonl"
@task
def build_mart(source_uri: str) -> str:
return "warehouse.analytics.fct_orders"
@task
def assert_row_count(table: str) -> None:
assert table == "warehouse.analytics.fct_orders"
assert_row_count(build_mart(extract()))
orders_daily_mart()The important contract is not the Python syntax; it is the dependency graph, schedule, retry boundary, and backfill behavior. catchup=True means missed logical dates are eligible for backfill, which is appropriate for batch-versus-streaming jobs that can replay a partition. max_active_runs=1 protects a warehouse table when two dates would otherwise mutate the same target concurrently.
Operational shape
Use Airflow for coordination, not row-by-row computation. Heavy transforms belong in the warehouse, Spark, Beam, or a service-specific job; the DAG should pass parameters, wait for completion, and record ownership. Dynamic task mapping is useful when a runtime list of partitions or tenants fans out into parallel tasks, but large maps create scheduler and observability overhead.
Failure modes
A green Airflow run proves task completion, not metric correctness. Hidden side effects make retries unsafe: a task that appends without an idempotency key can duplicate rows after a transient failure. DAG parse-time network calls slow the scheduler and can break unrelated workflows.
References
Nav
Section — Data Engineering