A DbtDag suits a dbt 37,942 project that runs on its own schedule. When dbt is one stage of a larger pipeline, a DbtTaskGroup drops the rendered graph into an ordinary DAG. booknest_daily_cosmos is Writing DAGs's pipeline with the BashOperator replaced:
sales_mart = DbtTaskGroup( # replaces the single BashOperator of 7.5
group_id="sales_mart",
project_config=PROJECT,
profile_config=PG_PROFILE,
execution_config=DBT_CORE,
render_config=RenderConfig(select=["+fct_sales", "+dim_book"]),
operator_args={"retries": 1}, # per model; a failed model reruns alone
)
...
ingest() >> sales_mart >> check() >> publish()select takes dbt's own syntax: +fct_sales is the fact table and everything upstream of it, so the group holds the three staging models and the seed they need, plus run-and-test pairs for fct_sales and dim_book, which publish joins. operator_args passes Airflow 129 arguments (retries, pools, queues) to every generated task, or dbt flags such as full_refresh. RenderConfig(test_behavior=...) sets the granularity of tests:
| TestBehavior | Tasks per model | Effect |
|---|---|---|
| AFTER_EACH (default) | Run, then test, in a group | Fails fast at the first bad model |
| BUILD | One dbt build task | Half the tasks, model and tests retried together |
| AFTER_ALL | One run task; tests at the end | dbt's own order |
| NONE | One run task | No tests |
ExecutionConfig decides where each task's dbt runs: LOCAL (a subprocess on the worker, as here), VIRTUALENV (a venv Cosmos creates), DOCKER or KUBERNETES (an image with the project baked in), cloud container services, AIRFLOW_ASYNC (deferrable, BigQuery 1 only) and WATCHER. The docs steer container modes to LoadMode.DBT_MANIFEST or CUSTOM, because the worker has no dbt to run dbt ls with.