The graph everything hangs off — and the trio interviews always test.
Your win: read a DAG's structure, declare dependencies, and crisply
distinguish a DAG from a DAG run from a task instance.
A DAG is tasks + edges, with no cycles
A DAG (Directed Acyclic Graph) is a set of
tasks connected by directed dependency edges — and it's
acyclic: no task can loop back to an earlier one.1
That "no cycles" rule is what guarantees a finite, well-defined order to run things in.
You declare the tasks first, then their dependencies with >>:
camel_job >> lrn_questions >> spark_app >> spark_val # a real chain in this repo
a >> [b, c] # fan-out: b and c both run after a
[b, c] >> d # fan-in: d runs after both b and c
a >> b reads "a is upstream of b" — b runs after a succeeds.
The trio: DAG vs DAG run vs task instance
Memorise this distinction
A DAG is the definition of the workflow. A DAG
run is one execution of it for a specific data interval (many can exist
— one per interval). A task instance is one run of one task within one
DAG run — and it's the thing that has a state (running / success / failed) and
gets retried.
Anchor
The chain above is our real sync-learnosity-data-with-val DAG
(airflow/dags/templates/sync-learnosity-data-with-val.py:102):
a Camel fetch, then Learnosity questions, then a Spark transform, then a Spark validation
— ordered by >>. ⚠️ It's generated from a template + a
rules.yaml entry, not hand-written (Lesson 10) — but the DAG it produces is
exactly this graph.
Backend use case
Backend use case: this is the reading model you need before the generated repo DAGs make sense, because every Python file rendered from `rules.yaml` is still just a DAG made of ordered tasks.
Common mistake
Common mistake: using “DAG”, “DAG run”, and “task” like they mean the same thing, which causes confusion in both interviews and debugging.
Read this next
Airflow — DAGs, Tasks & DAG Runs
The core-concepts pages for the DAG model, tasks, and the DAG-run/data-interval idea
(which we go deep on in Part 2).
In plain English
Plain English: a DAG is the workflow definition, tasks are the units of work, and dependencies are the arrows that say what must finish before something else can start.
Check yourself (from memory)
Q1. A DAG must be acyclic, meaning…
No cycles → a finite, well-defined execution order. You
can't have A depend on B that depends on A.
Q2.a >> b means…
a is upstream of b — b waits for a to succeed. Fan-out
with a >> [b, c].
Q3. A single execution of a DAG for one interval is a…
DAG run = one execution for a data interval; a task
instance is one task within that run.
Distinguish DAG, DAG run, and task instance; and how are dependencies declared?
recall, then click to reveal
A DAG is the DEFINITION — tasks + dependency edges, no cycles
(acyclic → a finite ordering). A DAG RUN is one EXECUTION for a specific data interval
(many can exist, one per interval). A TASK INSTANCE is one run of one task within one DAG
run — the thing with a state (running/success/failed) and retries. Dependencies use
>>: a >> b = b after a; a >> [b, c]
fans out; [b, c] >> d fans in. Our sync-learnosity-data-with-val
chains camel_job >> lrn_questions >> spark_app >> spark_val.
Want to see task groups, or how a diamond dependency (fan-out then fan-in) behaves on
failure? Ask me.