Support for Dependent/Cascading Dropdown Parameters in Trigger DAG UI
- Dominant language
- Python
- Stars
- 46.9k
- Forks
- 17.8k
- Avg merge
- 2d 9h
- Merged PRs (30d)
- 472
Description
### Description
When triggering a DAG via the Airflow web UI, there is no way to define **dependent (cascading) relationships** between `Param` dropdowns — where the selected value in one dropdown dynamically filters the available options in another.
For example, if a DAG has a `country` param and a `region` param, selecting **"Kenya"** should only show Kenyan regions (`Nandi County`, `Nyandarua`, `Nakuru`), and selecting **"Ethiopia"** should only show Ethiopian regions (`Jimma`, `Arsi`, etc.). Currently, all regions from all countries are shown in a **flat list** regardless of which country is selected.
---
### Current Workaround
The only option today is to flatten all child values into a single `enum` list and validate the parent-child pairing at runtime:
```python
from airflow.models.param import Param
from airflow.models import Variable
COUNTRY_REGIONS = Variable.get("country_region_mapping", deserialize_json=True)
# {
# "Kenya": {"Nandi County": "21802", "Nyandarua": "26727", "Nakuru": "26199"},
# "Ethiopia": {"Jimma": "123", "Arsi": "456"}
# }
COUNTRY_LIST = list(COUNTRY_REGIONS.keys())
# Flatten ALL regions into one list — no filtering by country
ALL_REGIONS = ["All Regions"]
for country in COUNTRY_REGIONS:
ALL_REGIONS.extend(list(COUNTRY_REGIONS[country].keys()))
dag_params = {
"country": Param(default="Kenya", enum=COUNTRY_LIST, type="string"),
"region": Param(
default="All Regions",
enum=ALL_REGIONS, # Shows ALL regions from ALL countries
description=" Ensure region matches the selected country",
),
}
```
> **Problems:**
> - Users can select mismatched pairs (e.g. `Kenya` + `Jimma`) — the DAG fails at runtime instead of preventing the mistake in the UI
> - The dropdown is cluttered with irrelevant options from other parent values
> - Does not scale as more countries/regions are added
> - Requires a dedicated validation task in every DAG that uses hierarchical params
---
### Proposed Solution — `depends_on` Attribute
Add a `depends_on` keyword to `Param` that references a parent param and maps each parent value to its valid child options:
```python
dag_params = {
"country": Param(
default="Kenya",
enum=["Kenya", "Ethiopia"],
type="string",
),
"region": Param(
default="Nandi County",
type="string",
depends_on={
"param": "country",
"mapping": {
"Kenya": ["All Regions", "Nandi County", "Nyandarua", "Nakuru"],
"Ethiopia": ["All Regions", "Jimma", "Arsi", "Shashemene"],
},
},
),
}
```
**How it would work in the Trigger Form UI:**
1. `country` renders as a normal dropdown
2. When `country` changes → the UI reads `region.depends_on.mapping[selectedCountry]` and updates `region`'s options
3. If the current `region` value is not in the new options → it resets to the first available option
4. Server-side validation on submit still validates the final values
---
### Implementation Notes
**Backend (Python):**
- Extend `airflow.models.param.Param` to accept a `depends_on` attribute
- Serialize the dependency metadata into the JSON Schema returned by the trigger form API endpoint
**Frontend (React — Trigger Form):**
- When rendering params, check if a param has `depends_on`
- Register an `onChange` listener on the parent param's dropdown
- On parent value change → update child dropdown options, reset child value if invalid
### Use case/motivation
This is a common requirement in **multi-country / multi-tenant data pipelines**.
Our team runs a project, which operates automated data quality pipelines across Kenya and Ethiopia. Each country has multiple sub-regions, and our DAGs need users to select a valid country → region pair when triggering reports. Without cascading support, we must flatten all regions into a single dropdown and add runtime validation — leading to avoidable DAG failures and a poor user experience.
This pattern appears frequently across many Airflow deployments:
| Parent Param | Child Param | Example |
|:---|:---|:---|
| Country | Region / Province | Multi-country data pipelines |
| Cloud Provider | Region / Zone | Infrastructure DAGs (`AWS` → `us-east-1`, `GCP` → `us-central1`) |
| Database | Schema / Table | ETL pipelines |
| Environment | Cluster | Deployment DAGs (`prod` → `prod-cluster-1`) |
| Department | Team | Org-scoped reporting DAGs |
| Data Source | Dataset | Analytics pipelines |
### Related issues
- #56632 — Dynamic DAG parameter options from external config (addresses dynamic enum values, but **not** cascading/dependent relationships between params)
- #56427 — DAG Params Enum not working as expected
- #42524 — DAG Param incorrectly converts enum objects to strings
- #31399 — Trigger UI Form Dropdowns with enums do not set default correctly
- #39904 — Dynamic DAG Params behave differently in manually triggered vs scheduled runs
- https://github.com/apache/airflow/discussions/48481 — Multiple-choice Params discussion
### Are you willing to submit a PR?
- [x] Yes I am willing to submit a PR!
### Code of Conduct
- [x] I agree to follow this project's [Code of Conduct](https://github.com/apache/airflow/blob/main/CODE_OF_CONDUCT.md)
Contributor guide
Research direction
Start with airflow.models.param.Param and the trigger form API endpoint to understand how parameter schemas are represented and serialized. Then inspect the React Trigger Form entry point for parameter rendering and change handling. Done means dependency metadata reaches the form, child options update and invalid values reset, and final values remain server-side validated.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python, react
- Domain
- backend, frontend
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 42/100