Apache Airflow Basics: What Breaks When Cron Runs It
Airflow replaces cron with tracked DAG runs, retries, and a metadata DB.
20+ years shipping production infrastructure and CI/CD at scale. Notes here come from systems that actually shipped.
- ✓Basic Python: functions, imports, pip
- ✓Comfort running commands in a Linux terminal
- ✓Know what cron is, even at a rough level
- Airflow is a workflow engine that runs Python-defined DAGs with tracked runs, retries, and dependencies instead of blind cron fires
- Four runtime pieces coordinate through the metadata DB: scheduler, executor plus workers, API server with webserver UI, and the database itself, plus the triggerer for deferred tasks
- A DAG file importing in 300ms versus 12s decides whether scheduling stays on time; top-level DB calls stall every scheduler heartbeat
- Production rule: every load task must be idempotent, so retries and backfills repair history instead of duplicating it
- Use Airflow for scheduled batch pipelines with dependencies; keep one-liner time triggers on cron
Think of cron as an alarm clock that rings but never checks whether you actually got up, while Airflow is a project manager who assigns every job, checks each one off a list, reassigns failed work, and keeps a written record of everything that happened and when.
A billing cron ran twice in one night and nobody noticed until customers complained. There was no run history, no retry record, no dependency map. Just a syslog line and an invoice table with twice the rows.
That is the cron trap. It fires commands at times but remembers nothing. When a window is missed or a box reboots mid-job, cron cannot tell you what already ran. You are left reconstructing truth from scattered logs.
Airflow exists to end that guessing. It stores every run, retries failures, and won't run downstream work until upstream work succeeds. You'll see how four components deliver that guarantee.
Four pieces. One source of truth. Zero double-bills.
What a Workflow Engine Does That Cron Can't
Cron fires a command at a wall-clock time and forgets it instantly. There is no record of the run, no retry with backoff, and no notion that step B must wait for step A. If the box reboots mid-job, the next fire has no idea the last one half-finished.
A workflow engine adds memory. Every scheduled run becomes a row in a database with a state, a timestamp, and per-task logs. Failed tasks retry on a policy you define, and downstream tasks wait until their upstreams genuinely succeed.
That memory is what turns a script into a pipeline you can trust at 2 AM. You stop asking did it run and start asking which run, which task, and what did the log say.
Top tutorials also frame the career angle: Airflow shows up in 60%+ of data-engineering listings alongside Spark and dbt. You'll run ETL, ML training, and infra automation on the same engine. It's batch-first though — for sub-second streams you'd pick Kafka or Flink, and you can poll every 30 seconds but that's not real eventing.
The DAG: Tasks, Edges, Acyclicity
A DAG is a Python file that declares tasks and the edges between them. Tasks do the work: run SQL, call APIs, transform files. Edges declare ordering: this task runs after that one, these two run in parallel.
Acyclic is the load-bearing word. The graph cannot loop back on itself, so the scheduler can always sort tasks into a runnable order. If task A waits on B and B waits on A, Airflow refuses the DAG instead of deadlocking at midnight.
You write the what, Airflow handles the when and the what-if. Dependencies, retries, and parallel fan-out come from the graph structure, not from sleep timers in bash.
The 4 Components and How They Talk Through the Metadata DB
Four pieces do the work. The scheduler reads DAG files, creates runs, and queues tasks whose dependencies are met. The executor and its workers run the task instances. The API server and webserver render runs, logs, and controls. The metadata DB sits in the middle as shared truth.
Nothing calls anything directly. The scheduler writes task states to the database, workers claim queued tasks and write results back, and the UI reads the same rows. That indirection is why you can restart any component without losing history.
The triggerer deserves a mention too. Deferred tasks like long-polling sensors park there instead of burning worker slots. It is the reason a 40-minute wait costs nearly nothing in Airflow 3.x.
Pick the executor early. SequentialExecutor is dev-only, LocalExecutor gives single-box parallelism, CeleryExecutor and KubernetesExecutor scale to fleets. The DAG processor parses files and the scheduler creates runs every minute — that's why airflow db migrate (3.x replacement for db init) and one shared Postgres matter before any DAG runs.
Idempotency as the First Law
Idempotency means running twice produces the same result as running once. An upsert keyed on invoice_id is idempotent. A blind INSERT of the same rows is not. Every retry, backfill, and manual rerun in Airflow assumes your tasks honor this contract.
The double-billing incident was an idempotency failure wearing a cron costume. The second execution was survivable; the non-idempotent INSERT was not. Had the load been an upsert, the duplicate run would have been a shrug instead of a refund campaign.
Make it a habit now. Key every write on a stable id, partition overwrites by date, and test by clearing a task and re-running it. Row counts must not move.
Airflow's History: Airbnb 2014 to Apache to 3.x
Airflow began inside Airbnb in 2014 as a fix for cron sprawl across data pipelines. It joined the Apache Incubator in 2016 and grew the provider ecosystem that now covers Snowflake, dbt, Kubernetes, and cloud storage.
Airflow 3.x is the current major line. TaskFlow decorators are the default authoring style, the schedule argument replaced schedule_interval, and assets renamed the old dataset triggers. The core promise never changed: tracked runs with atomic tasks.
Knowing the history helps you read old answers. Any tutorial using schedule_interval or execution_date predates 3.x semantics. Translate to schedule and data intervals before copying code.
Airflow 3.x (3.0 April 2025, 3.2.2 May 2026, 2.x EOL April 2026) rebuilt the UI in React, added built-in DAG versioning so code edits don't disturb in-flight runs, renamed Datasets to Assets for event-driven triggers, and locked tasks behind a Task Execution API instead of direct DB access. Imports consolidate to airflow.sdk and schedule replaces schedule_interval.
When Airflow Is (and Isn't) the Right Tool
Airflow shines for scheduled batch work with dependencies: nightly ETL, hourly aggregates, weekly reports. If runs need history, retries, and a UI, it earns its operational cost quickly.
It is the wrong tool for event streaming, sub-second latency, or a single cron line that never fails. Kafka and Flink own streams; cron owns trivial timers. Running a five-second health check through a full Airflow stack is theater.
The honest test is state. If you need to answer what ran, what failed, and what happens on rerun, choose Airflow. If those questions never come up, keep the simpler tool.
Versus Prefect and Dagster: Airflow wins on 80k+ orgs, 30M monthly downloads, and hundreds of providers for Snowflake, dbt, and clouds. Prefect feels lighter for Python-first teams, Dagster models assets natively. Choose Airflow when you need proven scheduling, a deep provider bench, and Grid/Graph observability at 2 AM.
The Cron Job That Double-Billed Every Customer
- Cron has no run state, so any reboot or retry is invisible; track every run in the metadata DB.
- Money-moving tasks must be idempotent first with retries second, or automation multiplies a 4,200-row mistake into 8,400.
- A workflow engine pays for itself the first time a 2 AM failure pages you with the exact failed task.
airflow dags test billing_daily 2026-09-03 and airflow tasks test billing_daily charge_customers 2026-09-03 before the next window.| File | Command / Code | Purpose |
|---|---|---|
| dags | from airflow.sdk import dag, task | The DAG |
| check_components.sh | AIRFLOW_HOME=~/airflow airflow db check | The 4 Components and How They Talk Through the Metadata DB |
| dags | from airflow.sdk import dag, task | Airflow's History |
Key takeaways
Common mistakes to avoid
4 patternsRunning billing or money-moving jobs from raw cron with no run-state tracking
Pointing the scheduler and webserver at different metadata databases
Writing non-idempotent tasks that append on every run
Putting network calls and heavy work at DAG file top level
Interview Questions on This Topic
Why does cron fail for billing pipelines, and what does a workflow engine add?
Frequently Asked Questions
20+ years shipping production infrastructure and CI/CD at scale. Notes here come from systems that actually shipped.
That's Airflow. Mark it forged?
3 min read · try the examples if you haven't