"Should we use Airflow or Glue?" is one of the most common questions we get, and it contains a hidden assumption that is worth dismantling before answering: that the two are alternatives. They are not. One is an orchestrator. The other is a compute engine that happens to ship a small orchestrator alongside it. Most mature platforms end up running both.
That said, there is a real decision underneath the confused question — and getting it wrong costs either money you did not need to spend or engineering months you did not budget.
The category error
Comparing Airflow to Glue is like comparing a project manager to a machinist. The project manager decides what happens in what order, notices when something is late, and reschedules. The machinist cuts metal. You can ask the machinist to keep a rough schedule, and for a small shop that is fine. It does not make them a project manager.
Concretely:
- Apache Airflow schedules and monitors workflows. It does not process your data. Every meaningful Airflow task delegates the actual work to something else — Glue, Spark, dbt, a warehouse, an API.
- AWS Glue processes data. It is serverless Spark plus a metadata catalog. It also ships Glue Workflows and Triggers, a lightweight orchestrator for chaining Glue jobs and crawlers.
So the honest form of the question is: "Are Glue Workflows enough, or do we need a real orchestrator?" That one has a useful answer.
What each one actually is
Apache Airflow
Workflows are Python. A DAG is a Python module, which means dependencies, branching and even the DAG's structure itself can be computed at parse time. That expressiveness is Airflow's entire value proposition.
An Airflow DAG driving Glue jobs
from airflow import DAG
from airflow.providers.amazon.aws.operators.glue import GlueJobOperator
from airflow.providers.amazon.aws.sensors.s3 import S3KeySensor
import pendulum
with DAG(
dag_id="clickstream_hourly",
schedule="@hourly",
start_date=pendulum.datetime(2026, 1, 1, tz="UTC"),
catchup=True, # backfill missed intervals automatically
max_active_runs=3,
default_args={"retries": 2},
) as dag:
wait_for_data = S3KeySensor(
task_id="wait_for_raw",
bucket_key="s3://delantech-lake/raw/events/dt={{ ds }}/hr={{ logical_date.hour }}/_SUCCESS",
poke_interval=60,
timeout=60 * 30,
mode="reschedule", # frees the worker slot while waiting
)
compact = GlueJobOperator(
task_id="compact",
job_name="events-compact",
script_args={"--dt": "{{ ds }}", "--hr": "{{ logical_date.hour }}"},
)
model = GlueJobOperator(task_id="model", job_name="events-model")
wait_for_data >> compact >> modelNote what Glue Workflows cannot express in that snippet: waiting on an external condition, templated run parameters derived from the scheduling interval, and automatic backfill of missed intervals.
Glue Workflows
Glue Workflows chain Glue jobs and crawlers using triggers: on a schedule, on completion of a predecessor, or on demand. Configuration is declarative, lives in the Glue console or your IaC, and requires no infrastructure of its own.
Glue Workflow — a conditional trigger
resource "aws_glue_trigger" "after_compact" {
name = "start-model-after-compact"
type = "CONDITIONAL"
workflow_name = aws_glue_workflow.clickstream.name
predicate {
conditions {
job_name = aws_glue_job.compact.name
state = "SUCCEEDED"
}
}
actions { job_name = aws_glue_job.model.name }
}For a linear chain of five jobs, this is genuinely simpler than standing up Airflow. The limits show up as the graph grows.
Where they genuinely overlap
The overlap is narrow and specific: sequencing a set of Glue jobs that all live inside AWS. Inside that box, Glue Workflows are adequate and cheaper. Outside it — the moment a pipeline touches an on-prem database, a SaaS API, a dbt run, a Snowflake task, or anything needing a backfill — Glue Workflows run out quickly.
A useful diagnostic: count the systems your pipeline touches that are not AWS data services. If the answer is zero, Glue Workflows may well be enough. If it is two or more, you are going to end up writing orchestration logic by hand, and you will do it worse than Airflow already does it.
The comparison, dimension by dimension
| Dimension | Apache Airflow | Glue Workflows |
|---|---|---|
| Primary role | Orchestration | Compute, with light orchestration attached |
| Definition | Python code — dynamic, testable, reviewable | Declarative triggers via console or IaC |
| Branching | Full conditional logic, branching, dynamic task mapping | Conditional triggers on job state only |
| Backfill | First-class: catchup, per-interval reruns, clear-and-replay | None. You re-run by hand. |
| Waiting on events | Sensors for S3, SQL, HTTP, external DAGs, plus deferrable operators | Not supported |
| Cross-system | 100+ provider packages covering AWS, Azure, GCP, Snowflake, Databricks, dbt, Kubernetes and many other platforms — roughly 2,000 operators, hooks and sensors between them | Glue jobs and crawlers |
| Retries | Per-task policies, exponential backoff, callbacks, SLA misses | Basic job-level retry |
| Observability | Grid/graph views, per-task logs, DAG-level history, Datasets lineage | Workflow run graph in the Glue console |
| Local testing | airflow dags test, pytest, Breeze — runs on a laptop | Effectively none |
| Ops burden | Real. Managed by MWAA, still yours to version and tune | None |
| Idle cost | Continuous — the scheduler always runs | Zero |
| Lock-in | Portable across clouds and on-prem | AWS only |
Cost: the floor is the difference
This is where the decision usually gets made, and the shape matters more than the exact figures.
Glue Workflows have no floor. Triggers and workflows are free; you pay only for the Glue jobs that run. A pipeline that runs twice a day costs you two job runs.
Airflow has a floor. The scheduler runs continuously whether or not you have work. On Amazon MWAA you pay for the environment by the hour, plus workers, plus metadata storage — on the order of a few hundred dollars a month for a small environment even if it orchestrates nothing. Self-managing on ECS or EKS trades that bill for engineering time, usually unfavorably.
Prices move and vary by region; check current AWS pricing before you build a business case. The structural point is stable: Glue Workflows cost zero when idle, Airflow costs the same when idle as when busy. Everything below follows from that.
Which means the break-even is not really about money — it is about how much orchestration logic you would otherwise write and maintain yourself. One team we worked with had accumulated 2,400 lines of Lambda glue code reimplementing retries, backfill and cross-account sequencing, precisely to avoid an Airflow bill a fraction of what that code cost to maintain.
When Glue alone is the right answer
Do not add Airflow if all of these hold:
- Fewer than roughly 10–15 pipelines, with mostly linear dependencies.
- Everything lives in AWS data services.
- Schedules are simple — hourly, daily — with no complex conditional logic.
- Backfills are rare and a manual re-run is acceptable.
- No team member is going to own Airflow. This one is disqualifying on its own.
Adding Airflow to a five-pipeline platform is a good way to acquire an operational burden with nothing to show for it. Glue Workflows plus EventBridge scheduling handle this shape well.
When you need Airflow
Any one of these is usually sufficient reason:
- Cross-system pipelines. Anything spanning AWS plus Snowflake, dbt, an on-prem warehouse, or a partner API.
- Backfills are routine. If "reprocess last March" is a normal request, Airflow's interval model is worth the whole cost on its own.
- Complex dependencies. Fan-out/fan-in, conditional branches, pipelines that wait on each other.
- Dynamic pipelines. One DAG generating N tasks from a config table or a customer list. Dynamic task mapping does this natively.
- Many teams, one platform. Airflow's UI is a shared operational surface; per-DAG ownership and a single place to see what is late.
- Data-aware scheduling. Triggering a DAG when an upstream dataset updates rather than at a fixed time.
The pattern we deploy most: both
For any platform past the early stage, the answer is almost always Airflow orchestrates, Glue computes. Each does the thing it is actually good at, and neither is asked to do the other's job.
Two implementation details that matter more than they look:
Use deferrable operators. A standard operator occupies a worker slot for the entire duration of a Glue job. A deferrable one hands off to the triggerer and frees the slot. On a platform with dozens of concurrent long-running jobs, this is the difference between 4 workers and 40.
Deferrable operator — do not burn a worker slot waiting
from airflow.providers.amazon.aws.operators.glue import GlueJobOperator
model = GlueJobOperator(
task_id="model",
job_name="events-model",
deferrable=True, # release the worker slot while Glue runs
wait_for_completion=True,
)Keep business logic out of the DAG. The DAG says what runs, in what order, and what to do on failure. It should contain no transformation logic whatsoever. If you find yourself manipulating data inside an Airflow task, that work belongs in a Glue job — the Airflow worker is not sized for it, and you have just made your orchestrator a single point of failure for compute.
Where Step Functions fits
AWS Step Functions is the frequently overlooked third option, and for some shapes it is the best of the three.
| Step Functions | Airflow | Glue Workflows | |
|---|---|---|---|
| Cost when idle | Zero | Continuous | Zero |
| Branching & parallelism | Good (Choice, Map, Parallel) | Excellent | Minimal |
| Backfill | Manual | First-class | Manual |
| AWS service integration | Excellent — direct SDK integrations | Good, via providers | Glue only |
| Non-AWS systems | Poor | Excellent | None |
| Authoring | ASL (JSON) or CDK | Python | Console / IaC |
| Ops burden | None | Real | None |
Step Functions is the sweet spot when you need real branching and error handling across AWS services, have no idle budget, and do not need backfill or non-AWS integrations. It is a poor fit when pipelines are data-interval-shaped, because it has no concept of a scheduling interval to backfill over.
A decision framework
In order. Stop at the first "yes".
- Does the pipeline touch systems outside AWS, or need routine backfills?
→ Airflow, with Glue as the compute layer. - Do you need substantial conditional branching across AWS services, with no idle spend?
→ Step Functions, with Glue as the compute layer. - Is it a handful of Glue jobs in a mostly linear chain, all inside AWS?
→ Glue Workflows. Revisit when you pass roughly 15 pipelines. - Is there nobody to own an orchestrator?
→ Glue Workflows, regardless of the above. An unowned Airflow is worse than no Airflow.
The most common mistake we see is not choosing wrong — it is choosing once and never revisiting. Glue Workflows are the right call for a platform with six pipelines and the wrong one for the same platform two years later with sixty. Put a review on the calendar rather than waiting for the pain.
Migrating from Glue Workflows to Airflow
If you outgrow Glue Workflows, the migration is more tractable than it looks, because the Glue jobs themselves do not change at all — only what triggers them.
- Inventory the triggers. Each Glue trigger becomes an edge in an Airflow DAG. Conditional triggers map to task dependencies; scheduled triggers become DAG schedules.
- Move one pipeline first. Pick a low-stakes daily job. Run it in Airflow alongside the existing workflow for a week and compare outputs.
- Disable, do not delete. Keep the Glue triggers disabled rather than removed until the Airflow version has survived a full cycle including a failure.
- Add what you migrated for. Sensors, backfill, retries, alerting. If you migrate and do not use these, you have taken on cost for nothing.
- Then consolidate. Only once several pipelines are running should you factor out shared DAG utilities. Premature abstraction here produces DAG factories nobody can debug.
Whichever orchestrator you land on, the compute layer underneath is where the performance and cost actually live. Our companion piece walks through building those Glue jobs properly: Building Production Data Pipelines with AWS Glue and PySpark.
Running into these problems on your own platform?
We do free data platform assessments — we map your pipelines, surface quick wins, and hand you a 90-day engineering roadmap.
Book an assessment