
Cosmos Dbt Core
- 810 installs
- 412 repo stars
- Updated July 27, 2026
- astronomer/agents
cosmos-dbt-core is an Astronomer agent skill that converts a dbt Core project into a production-ready Airflow DAG or DbtTaskGroup using Astronomer Cosmos 1.11+ with Airflow 3.x compatibility guidance.
About
cosmos-dbt-core is an Astronomer/agents implementation checklist for wiring dbt Core into Airflow via astronomer-cosmos. The skill targets Cosmos 1.11+ and Airflow 3.x, with Appendix A notes for Airflow 2.x import differences. Eight ordered steps cover ProjectConfig, RenderConfig load modes (dbt_manifest, dbt_ls, dbt_ls_file, automatic), ExecutionConfig modes from WATCHER through KUBERNETES, ProfileConfig with SnowflakeUserPasswordProfileMapping or profiles.yml, TestBehavior settings, operator_args, and final DbtDag or DbtTaskGroup assembly. Safety checks enforce secrets via Airflow connections, correct load mode for containerized execution, and BigQuery-only constraints on AIRFLOW_ASYNC. Reach for cosmos-dbt-core when a dbt Core manifest or project path exists and you need Cosmos DAG code—not dbt Fusion, which requires cosmos-dbt-fusion instead.
- Executes a strict 6-point pre-flight checklist before any code generation
- Supports both ProjectConfig (dbt_project_path) and manifest-only loading modes
- Targets Cosmos 1.11+ and Airflow 3.x with explicit Airflow 2.x fallback instructions
- Generates clean, minimal configuration preferring simplest setup that satisfies constraints
- Includes version-specific import guidance and appendix references
Cosmos Dbt Core by the numbers
- 810 all-time installs (skills.sh)
- +15 installs in the week ending Jul 28, 2026 (Skillselion tracking)
- Ranked #1,300 of 16,659 AI & Agent Building skills by installs in the Skillselion catalog
- Security screen: MEDIUM risk (skills.sh audit)
- Data as of Jul 28, 2026 (Skillselion catalog sync)
npx skills add https://github.com/astronomer/agents --skill cosmos-dbt-coreAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 810 |
|---|---|
| repo stars | ★ 412 |
| Security audit | 2 / 3 scanners passed |
| Last updated | July 27, 2026 |
| Repository | astronomer/agents ↗ |
How do you turn a dbt Core project into Airflow DAGs?
Convert an existing dbt Core project into a production-ready Airflow DAG or TaskGroup using Astronomer Cosmos.
Who is it for?
Data engineers with an existing dbt Core project and Airflow 3.x or 2.x who need Cosmos 1.11+ DAG or TaskGroup code with correct load and execution modes.
Skip if: dbt Fusion projects without Core, greenfield apps with no dbt models, or teams not running Apache Airflow.
When should I use this skill?
User asks to schedule dbt Core models in Airflow, configure DbtDag, DbtTaskGroup, or Cosmos ProfileConfig for a warehouse connection.
What you get
Runnable DbtDag or DbtTaskGroup Python module with ProjectConfig, ProfileConfig, ExecutionConfig, and RenderConfig aligned to warehouse and manifest constraints.
- DbtDag or DbtTaskGroup Python file
- ProfileConfig wiring
- RenderConfig load mode selection
By the numbers
- Eight-step implementation checklist in SKILL.md
- Targets Cosmos 1.11+ and Airflow 3.x
- Four documented RenderConfig load modes plus multiple ExecutionConfig modes
Files
Cosmos + dbt Core: Implementation Checklist
Execute steps in order. Prefer the simplest configuration that meets the user's constraints.
Version note: This skill targets Cosmos 1.11+ and Airflow 3.x. If the user is on Airflow 2.x, adjust imports accordingly (see Appendix A).
>
Reference: Latest stable: https://pypi.org/project/astronomer-cosmos/
Before starting, confirm: (1) dbt engine = Core (not Fusion → use cosmos-dbt-fusion), (2) warehouse type, (3) Airflow version, (4) execution environment (Airflow env / venv / container), (5) DbtDag vs DbtTaskGroup vs individual operators, (6) manifest availability.
---
1. Configure Project (ProjectConfig)
| Approach | When to use | Required param |
|---|---|---|
| Project path | Files available locally | dbt_project_path |
| Manifest only | dbt_manifest load | manifest_path + project_name |
from cosmos import ProjectConfig
_project_config = ProjectConfig(
dbt_project_path="/path/to/dbt/project",
# manifest_path="/path/to/manifest.json", # for dbt_manifest load mode
# project_name="my_project", # if using manifest_path without dbt_project_path
# install_dbt_deps=False, # if deps precomputed in CI
)2. Choose Parsing Strategy (RenderConfig)
Pick ONE load mode based on constraints:
| Load mode | When to use | Required inputs | Constraints |
|---|---|---|---|
dbt_manifest | Large projects; containerized execution; fastest | ProjectConfig.manifest_path | Remote manifest needs manifest_conn_id |
dbt_ls | Complex selectors; need dbt-native selection | dbt installed OR dbt_executable_path | Can also be used with containerized execution |
dbt_ls_file | dbt_ls selection without running dbt_ls every parse | RenderConfig.dbt_ls_path | select/exclude won't work |
automatic (default) | Simple setups; let Cosmos pick | (none) | Falls back: manifest → dbt_ls → custom |
CRITICAL: Containerized execution (DOCKER/KUBERNETES/etc.)
from cosmos import RenderConfig, LoadMode
_render_config = RenderConfig(
load_method=LoadMode.DBT_MANIFEST, # or DBT_LS, DBT_LS_FILE, AUTOMATIC
)---
3. Choose Execution Mode (ExecutionConfig)
Reference: See [reference/cosmos-config.md](reference/cosmos-config.md#execution-modes-executionconfig) for detailed configuration examples per mode.
Pick ONE execution mode:
| Execution mode | When to use | Speed | Required setup |
|---|---|---|---|
WATCHER | Fastest; single dbt build visibility | Fastest | dbt adapter in env OR dbt_executable_path or dbt Fusion |
WATCHER_KUBERNETES | Fastest isolated method; single dbt build visibility | Fast | dbt installed in container |
LOCAL + DBT_RUNNER | dbt + adapter in the same Python installation as Airflow | Fast | dbt 1.5+ in requirements.txt |
LOCAL + SUBPROCESS | dbt + adapter available in the Airflow deployment, in an isolated Python installation | Medium | dbt_executable_path |
AIRFLOW_ASYNC | BigQuery + long-running transforms | Fast | Airflow ≥2.8; provider deps |
KUBERNETES | Isolation between Airflow and dbt | Medium | Airflow ≥2.8; provider deps |
VIRTUALENV | Can't modify image; runtime venv | Slower | py_requirements in operator_args |
| Other containerized approaches | Support Airflow and dbt isolation | Medium | container config |
from cosmos import ExecutionConfig, ExecutionMode
_execution_config = ExecutionConfig(
execution_mode=ExecutionMode.WATCHER, # or LOCAL, VIRTUALENV, AIRFLOW_ASYNC, KUBERNETES, etc.
)---
4. Configure Warehouse Connection (ProfileConfig)
Reference: See [reference/cosmos-config.md](reference/cosmos-config.md#profileconfig-warehouse-connection) for detailed ProfileConfig options and all ProfileMapping classes.
Option A: Airflow Connection + ProfileMapping (Recommended)
from cosmos import ProfileConfig
from cosmos.profiles import SnowflakeUserPasswordProfileMapping
_profile_config = ProfileConfig(
profile_name="default",
target_name="dev",
profile_mapping=SnowflakeUserPasswordProfileMapping(
conn_id="snowflake_default",
profile_args={"schema": "my_schema"},
),
)Option B: Existing profiles.yml
CRITICAL: Do not hardcode secrets; use environment variables.
from cosmos import ProfileConfig
_profile_config = ProfileConfig(
profile_name="my_profile",
target_name="dev",
profiles_yml_filepath="/path/to/profiles.yml",
)---
5. Configure Testing Behavior (RenderConfig)
Reference: See [reference/cosmos-config.md](reference/cosmos-config.md#testing-behavior-renderconfig) for detailed testing options.
| TestBehavior | Behavior |
|---|---|
AFTER_EACH (default) | Tests run immediately after each model (default) |
BUILD | Combine run + test into single dbt build |
AFTER_ALL | All tests after all models complete |
NONE | Skip tests |
from cosmos import RenderConfig, TestBehavior
_render_config = RenderConfig(
test_behavior=TestBehavior.AFTER_EACH,
)---
6. Configure operator_args
Reference: See [reference/cosmos-config.md](reference/cosmos-config.md#operator_args-configuration) for detailed operator_args options.
_operator_args = {
# BaseOperator params
"retries": 3,
# Cosmos-specific params
"install_deps": False,
"full_refresh": False,
"quiet": True,
# Runtime dbt vars (XCom / params)
"vars": '{"my_var": "{{ ti.xcom_pull(task_ids=\'pre_dbt\') }}"}',
}---
7. Assemble DAG / TaskGroup
Option A: DbtDag (Standalone)
from cosmos import DbtDag, ProjectConfig, ProfileConfig, ExecutionConfig, RenderConfig
from cosmos.profiles import SnowflakeUserPasswordProfileMapping
from pendulum import datetime
_project_config = ProjectConfig(
dbt_project_path="/usr/local/airflow/dbt/my_project",
)
_profile_config = ProfileConfig(
profile_name="default",
target_name="dev",
profile_mapping=SnowflakeUserPasswordProfileMapping(
conn_id="snowflake_default",
),
)
_execution_config = ExecutionConfig()
_render_config = RenderConfig()
my_cosmos_dag = DbtDag(
dag_id="my_cosmos_dag",
project_config=_project_config,
profile_config=_profile_config,
execution_config=_execution_config,
render_config=_render_config,
operator_args={},
start_date=datetime(2025, 1, 1),
schedule="@daily",
)Option B: DbtTaskGroup (Inside Existing DAG)
from airflow.sdk import dag, task # Airflow 3.x
# from airflow.decorators import dag, task # Airflow 2.x
from airflow.models.baseoperator import chain
from cosmos import DbtTaskGroup, ProjectConfig, ProfileConfig, ExecutionConfig, RenderConfig
from pendulum import datetime
_project_config = ProjectConfig(dbt_project_path="/usr/local/airflow/dbt/my_project")
_profile_config = ProfileConfig(profile_name="default", target_name="dev")
_execution_config = ExecutionConfig()
_render_config = RenderConfig()
@dag(start_date=datetime(2025, 1, 1), schedule="@daily")
def my_dag():
@task
def pre_dbt():
return "some_value"
dbt = DbtTaskGroup(
group_id="dbt_project",
project_config=_project_config,
profile_config=_profile_config,
execution_config=_execution_config,
render_config=_render_config,
)
@task
def post_dbt():
pass
chain(pre_dbt(), dbt, post_dbt())
my_dag()Option C: Use Cosmos operators directly
import os
from datetime import datetime
from pathlib import Path
from typing import Any
from airflow import DAG
try:
from airflow.providers.standard.operators.python import PythonOperator
except ImportError:
from airflow.operators.python import PythonOperator
from cosmos import DbtCloneLocalOperator, DbtRunLocalOperator, DbtSeedLocalOperator, ProfileConfig
from cosmos.io import upload_to_aws_s3
DEFAULT_DBT_ROOT_PATH = Path(__file__).parent / "dbt"
DBT_ROOT_PATH = Path(os.getenv("DBT_ROOT_PATH", DEFAULT_DBT_ROOT_PATH))
DBT_PROJ_DIR = DBT_ROOT_PATH / "jaffle_shop"
DBT_PROFILE_PATH = DBT_PROJ_DIR / "profiles.yml"
DBT_ARTIFACT = DBT_PROJ_DIR / "target"
profile_config = ProfileConfig(
profile_name="default",
target_name="dev",
profiles_yml_filepath=DBT_PROFILE_PATH,
)
def check_s3_file(bucket_name: str, file_key: str, aws_conn_id: str = "aws_default", **context: Any) -> bool:
"""Check if a file exists in the given S3 bucket."""
from airflow.providers.amazon.aws.hooks.s3 import S3Hook
s3_key = f"{context['dag'].dag_id}/{context['run_id']}/seed/0/{file_key}"
print(f"Checking if file {s3_key} exists in S3 bucket...")
hook = S3Hook(aws_conn_id=aws_conn_id)
return hook.check_for_key(key=s3_key, bucket_name=bucket_name)
with DAG("example_operators", start_date=datetime(2024, 1, 1), catchup=False) as dag:
seed_operator = DbtSeedLocalOperator(
profile_config=profile_config,
project_dir=DBT_PROJ_DIR,
task_id="seed",
dbt_cmd_flags=["--select", "raw_customers"],
install_deps=True,
append_env=True,
)
check_file_uploaded_task = PythonOperator(
task_id="check_file_uploaded_task",
python_callable=check_s3_file,
op_kwargs={
"aws_conn_id": "aws_s3_conn",
"bucket_name": "cosmos-artifacts-upload",
"file_key": "target/run_results.json",
},
)
run_operator = DbtRunLocalOperator(
profile_config=profile_config,
project_dir=DBT_PROJ_DIR,
task_id="run",
dbt_cmd_flags=["--models", "stg_customers"],
install_deps=True,
append_env=True,
)
clone_operator = DbtCloneLocalOperator(
profile_config=profile_config,
project_dir=DBT_PROJ_DIR,
task_id="clone",
dbt_cmd_flags=["--models", "stg_customers", "--state", DBT_ARTIFACT],
install_deps=True,
append_env=True,
)
seed_operator >> run_operator >> clone_operator
seed_operator >> check_file_uploaded_taskSetting Dependencies on Individual Cosmos Tasks
from cosmos import DbtDag, DbtResourceType
from airflow.sdk import task, chain
with DbtDag(...) as dag:
@task
def upstream_task():
pass
_upstream = upstream_task()
for unique_id, dbt_node in dag.dbt_graph.filtered_nodes.items():
if dbt_node.resource_type == DbtResourceType.SEED:
my_dbt_task = dag.tasks_map[unique_id]
chain(_upstream, my_dbt_task)---
8. Safety Checks
Before finalizing, verify:
- [ ] Execution mode matches constraints (AIRFLOW_ASYNC → BigQuery only)
- [ ] Warehouse adapter installed for chosen execution mode
- [ ] Secrets via Airflow connections or env vars, NOT plaintext
- [ ] Load mode matches execution (complex selectors → dbt_ls)
- [ ] Airflow 3 asset URIs if downstream DAGs scheduled on Cosmos assets (see Appendix A)
---
Appendix A: Airflow 3 Compatibility
Import Differences
| Airflow 3.x | Airflow 2.x |
|---|---|
from airflow.sdk import dag, task | from airflow.decorators import dag, task |
from airflow.sdk import chain | from airflow.models.baseoperator import chain |
Asset/Dataset URI Format Change
Cosmos ≤1.9 (Airflow 2 Datasets):
postgres://0.0.0.0:5434/postgres.public.ordersCosmos ≥1.10 (Airflow 3 Assets):
postgres://0.0.0.0:5434/postgres/public/ordersCRITICAL: Update asset URIs when upgrading to Airflow 3.
---
Appendix B: Operational Extras
Caching
Cosmos caches artifacts to speed up parsing. Enabled by default.
Reference: https://astronomer.github.io/astronomer-cosmos/configuration/caching.html
Memory-Optimized Imports
AIRFLOW__COSMOS__ENABLE_MEMORY_OPTIMISED_IMPORTS=TrueWhen enabled:
from cosmos.airflow.dag import DbtDag # instead of: from cosmos import DbtDagArtifact Upload to Object Storage
AIRFLOW__COSMOS__REMOTE_TARGET_PATH=s3://bucket/target_dir/
AIRFLOW__COSMOS__REMOTE_TARGET_PATH_CONN_ID=aws_defaultfrom cosmos.io import upload_to_cloud_storage
my_dag = DbtDag(
# ...
operator_args={"callback": upload_to_cloud_storage},
)dbt Docs Hosting (Airflow 3.1+ / Cosmos 1.11+)
AIRFLOW__COSMOS__DBT_DOCS_PROJECTS='{
"my_project": {
"dir": "s3://bucket/docs/",
"index": "index.html",
"conn_id": "aws_default",
"name": "My Project"
}
}'Reference: https://astronomer.github.io/astronomer-cosmos/configuration/hosting-docs.html
---
Related Skills
- cosmos-dbt-fusion: For dbt Fusion projects (not dbt Core)
- authoring-dags: General DAG authoring patterns
- testing-dags: Testing DAGs after creation
Cosmos Configuration Reference (Core)
This reference covers detailed Cosmos configuration for dbt Core projects.
Table of Contents
- ProjectConfig Options
- Execution Modes (ExecutionConfig)
- ProfileConfig: Warehouse Connection
- Testing Behavior (RenderConfig)
- operator_args Configuration
- Airflow 3 Compatibility
--
ProjectConfig Options
Required Parameters
| Approach | When to use | Required param |
|---|---|---|
| Project path | Project files available locally | dbt_project_path |
| Manifest only | Using dbt_manifest load mode; containerized execution | manifest_path + project_name |
Optional Parameters
| Parameter | Purpose | Constraint |
|---|---|---|
dbt_project_path | The path to the dbt project directory. Defaults to None | Mandatory if using LoadMode.DBT_LS |
manifest_path | Path to precomputed manifest.json (local or remote URI). Defaults to None | Mandatory if using LoadMode.DBT_MANIFEST. Remote URIs require manifest_conn_id |
manifest_conn_id | Airflow connection for remote manifest (S3/GCS/Azure) | — |
install_dbt_deps | Run dbt deps during parsing/execution | Set False if deps are precomputed in CI |
copy_dbt_packages | Copy dbt_packages directory, if it exists, instead of creating a symbolic link (False by default) | Use in case user pre-computes dependencies, but they may change after the deployment was made. |
env_vars | Dict of env vars for parsing + execution | Requires dbt_ls load mode |
dbt_vars | Dict of dbt vars (passed to --vars) | Requires dbt_ls or custom load mode |
partial_parse | Enable dbt partial parsing | Requires dbt_ls load mode + local or virtualenv execution + profiles_yml_filepath |
models_relative_path | The relative path to the dbt models directory within the project. Defaults to models | — |
seeds_relative_path | The relative path to the dbt seeds directory within the project. Defaults to seeds | — |
snapshots_relative_path | The relative path to the dbt snapshots directory within the project. Defaults to snapshots | - |
WARNING: If usingdbt_varswith Airflow templates liketi,task_instance, orparams→ useoperator_args["vars"]instead. Those cannot be set viaProjectConfigbecause it is used during DAG parsing.
from cosmos import ProjectConfig
_project_config = ProjectConfig(
dbt_project_path="/path/to/dbt/project",
# manifest_path="/path/to/manifest.json",
# project_name="my_project",
# manifest_conn_id="aws_default",
# install_dbt_deps=False,
# copy_dbt_packages=False,
# dbt_vars={"my_var": "value"}, # static vars only
# env_vars={"MY_ENV": "value"},
# partial_parse=True,
# models_relative_path="custom_models_path",
# seeds_relative_path="custom_seeds_path",
# snapshots_relative_path="custom_snapshots_path",
)---
Execution Modes (ExecutionConfig)
WATCHER Mode (Experimental, Fastest)
Known limitations:
- Implements
DbtSeedWatcherOperator,DbtSnapshotWatcherOperatorandDbtRunWatcherOperator- not other operators - Built on top of
ExecutionMode.LOCALandExecutionMode.KUBERNETES- not available for other execution modes - Tests with
TestBehavior.AFTER_EACH, which is the default test behavior, are still being rendered as EmptyOperators. - May not work as expected when using
RenderConfig.node_converters - Airflow assets or datasets are emitted by the
DbtProducerWatcherOperatorinstead by the actual tasks related to the correspondent dbt models.
from cosmos import ExecutionConfig, ExecutionMode
_execution_config = ExecutionConfig(
execution_mode=ExecutionMode.WATCHER,
)Reference: https://astronomer.github.io/astronomer-cosmos/getting_started/watcher-execution-mode.html
LOCAL Mode (Default)
from cosmos import ExecutionConfig, ExecutionMode, InvocationMode
# Option A: dbt in Airflow env
_execution_config = ExecutionConfig(
execution_mode=ExecutionMode.LOCAL,
invocation_mode=InvocationMode.DBT_RUNNER,
)
# Option B: dbt in separate venv baked into image
_execution_config = ExecutionConfig(
execution_mode=ExecutionMode.LOCAL,
invocation_mode=InvocationMode.SUBPROCESS,
dbt_executable_path="/path/to/venv/bin/dbt",
)VIRTUALENV Mode
from cosmos import ExecutionConfig, ExecutionMode
_execution_config = ExecutionConfig(
execution_mode=ExecutionMode.VIRTUALENV,
virtualenv_dir="/path/to/persistent/cache",
)
_operator_args = {
"py_system_site_packages": False,
"py_requirements": ["dbt-<adapter>==<version>"],
"install_deps": True,
}AIRFLOW_ASYNC Mode (BigQuery Only)
CRITICAL: BigQuery only, Airflow ≥2.8 required.
Required setup: 1. Install: apache-airflow-providers-google 2. Set env vars:
AIRFLOW__COSMOS__REMOTE_TARGET_PATH=gs://bucket/target_dir/AIRFLOW__COSMOS__REMOTE_TARGET_PATH_CONN_ID= connection ID
from cosmos import ExecutionConfig, ExecutionMode
_execution_config = ExecutionConfig(
execution_mode=ExecutionMode.AIRFLOW_ASYNC,
async_py_requirements=["dbt-bigquery==<version>"],
)
_operator_args = {
"location": "US",
"install_deps": True,
}Reference: https://astronomer.github.io/astronomer-cosmos/getting_started/async-execution-mode.html
Containerized Modes
Available: DOCKER, KUBERNETES, AWS_EKS, AZURE_CONTAINER_INSTANCE, GCP_CLOUD_RUN_JOB, AWS_ECS.
CRITICAL: MUST use dbt_manifest load mode.from cosmos import ExecutionConfig, ExecutionMode, RenderConfig, LoadMode
_execution_config = ExecutionConfig(
execution_mode=ExecutionMode.KUBERNETES,
dbt_project_path="/path/to/dbt/project/in/image",
)
_render_config = RenderConfig(
load_method=LoadMode.DBT_MANIFEST,
)
_operator_args = {
"image": "dbt-jaffle-shop:1.0.0",
}---
ProfileConfig: Warehouse Connection
ProfileMapping Classes by Warehouse
| Warehouse | dbt Adapter Package | ProfileMapping Class |
|---|---|---|
| Snowflake | dbt-snowflake | SnowflakeUserPasswordProfileMapping |
| BigQuery | dbt-bigquery | GoogleCloudServiceAccountFileProfileMapping |
| Databricks | dbt-databricks | DatabricksTokenProfileMapping |
| Postgres | dbt-postgres | PostgresUserPasswordProfileMapping |
| Redshift | dbt-redshift | RedshiftUserPasswordProfileMapping |
| DuckDB | dbt-duckdb | DuckDBUserPasswordProfileMapping |
Full list: https://astronomer.github.io/astronomer-cosmos/profiles/index.html
Option A: Airflow Connection + ProfileMapping (Recommended)
from cosmos import ProfileConfig
from cosmos.profiles import SnowflakeUserPasswordProfileMapping
_profile_config = ProfileConfig(
profile_name="default", # REQUIRED
target_name="dev", # REQUIRED
profile_mapping=SnowflakeUserPasswordProfileMapping(
conn_id="snowflake_default", # REQUIRED
profile_args={"schema": "my_schema"}, # OPTIONAL
),
)Option B: Existing profiles.yml File
CRITICAL: Do not hardcode secrets in profiles.yml; use environment variables.from cosmos import ProfileConfig
_profile_config = ProfileConfig(
profile_name="my_profile", # REQUIRED: must match profiles.yml
target_name="dev", # REQUIRED: must match profiles.yml
profiles_yml_filepath="/path/to/profiles.yml", # REQUIRED
)Per-Node Profile Override
Override profile for individual nodes via dbt_project.yml:
# In dbt_project.yml or models/*.yml
version: 2
models:
- name: my_model
meta:
cosmos:
profile_config:
profile_name: other_profile
target_name: prod
profile_mapping:
conn_id: other_connection
profile_args:
schema: prod---
Testing Behavior (RenderConfig)
TestBehavior Options
| Option | Behavior | When to use |
|---|---|---|
AFTER_EACH | Run tests on each model immediately after model runs | Default; maximum visibility |
BUILD | Combine dbt run + dbt test into single dbt build per node | Faster parsing + execution |
AFTER_ALL | Run all tests after all models complete | Matches dbt CLI default behavior |
NONE | Skip tests entirely | When tests run separately |
NOTE: Cosmos default (AFTER_EACH) differs from dbt CLI default (AFTER_ALL).
Multi-Parent Test Handling
If a test depends on multiple models, AFTER_EACH may fail because not all parent models are materialized yet.
Solution: Set should_detach_multiple_parents_tests=True to run multi-parent tests only after all their parents complete.
from cosmos import RenderConfig, TestBehavior
_render_config = RenderConfig(
test_behavior=TestBehavior.AFTER_EACH, # default
# should_detach_multiple_parents_tests=True, # for multi-parent tests
)test_indirect_selection (For Subset Runs)
When running only part of a project (select/exclude), control which tests run. Set in ExecutionConfig:
| Option | Behavior |
|---|---|
eager | Run test if ANY parent is selected (may fail if other parents not built) |
buildable | Run test only if selected node or its ancestors are selected |
cautious | Only run tests for explicitly selected models |
empty | Run no tests |
from cosmos import ExecutionConfig, TestIndirectSelection
_execution_config = ExecutionConfig(
test_indirect_selection=TestIndirectSelection.CAUTIOUS,
)on_warning_callback
Execute a function when dbt tests generate warnings (works with local, virtualenv, kubernetes execution modes):
from airflow.utils.context import Context
def warning_callback(context: Context):
tests = context.get("test_names")
results = context.get("test_results")
# Send to Slack, email, etc.
my_dag = DbtDag(
# ...
on_warning_callback=warning_callback,
)---
operator_args Configuration
The operator_args dict accepts four categories of parameters:
Parameter Categories
| Category | Examples |
|---|---|
| BaseOperator params | retries, retry_delay, on_failure_callback, pool |
| Cosmos-specific params | install_deps, full_refresh, quiet, fail_fast, cancel_query_on_kill, warn_error, dbt_cmd_flags, dbt_cmd_global_flags |
| Runtime dbt vars | vars (string that renders as YAML) |
| Container operator params | image, namespace, secrets (for containerized execution) |
Example Configuration
_operator_args = {
# BaseOperator params
"retries": 3,
"on_failure_callback": my_callback_function,
# Cosmos-specific params
"install_deps": False, # if deps precomputed
"full_refresh": False, # for incremental models
"quiet": True, # only log errors
"fail_fast": True, # exit immediately on failure
# Container params (for containerized execution)
"image": "my-dbt-image:latest",
"namespace": "airflow",
}Passing dbt vars at Runtime (XCom / Params)
Use operator_args["vars"] to pass values from upstream tasks or Airflow params:
WARNING:operator_args["vars"]overrides ALL vars inProjectConfig.dbt_vars.
# Pull from upstream task via XCom
_operator_args = {
"vars": '{"my_department": "{{ ti.xcom_pull(task_ids=\'pre_dbt\', key=\'return_value\') }}"}',
}
# Pull from Airflow params (for manual runs)
@dag(params={"my_department": "Engineering"})
def my_dag():
dbt = DbtTaskGroup(
# ...
operator_args={
"vars": '{"my_department": "{{ params.my_department }}"}',
},
)Per-Node Operator Overrides
Override task parameters for individual nodes via dbt_project.yml:
# In dbt_project.yml or models/*.yml
version: 2
models:
- name: my_model
meta:
cosmos:
operator_kwargs:
retries: 10
pool: "high_priority_pool"---
Airflow 3 Compatibility
Import Differences
| Airflow 3.x | Airflow 2.x |
|---|---|
from airflow.sdk import dag, task | from airflow.decorators import dag, task |
from airflow.sdk import chain | from airflow.models.baseoperator import chain |
Asset/Dataset URI Format Change
Cosmos ≤1.9 (Airflow 2 Datasets):
postgres://0.0.0.0:5434/postgres.public.ordersCosmos ≥1.10 (Airflow 3 Assets):
postgres://0.0.0.0:5434/postgres/public/ordersCRITICAL: If you have downstream DAGs scheduled on Cosmos-generated datasets and are upgrading to Airflow 3, update the asset URIs to the new format.
DAG Versioning
DAG versioning in Airflow 3 does not yet track dbt project changes unless model names change. Improved support planned for Cosmos 1.11+.
Related skills
How it compares
Use cosmos-dbt-core for dbt Core orchestration; switch to cosmos-dbt-fusion when the project runs on dbt Fusion instead of Core.
FAQ
Which Cosmos and Airflow versions does cosmos-dbt-core target?
cosmos-dbt-core targets Astronomer Cosmos 1.11+ and Airflow 3.x by default. Appendix A documents Airflow 2.x import differences such as airflow.decorators versus airflow.sdk.
Should dbt Fusion projects use cosmos-dbt-core?
cosmos-dbt-core is for dbt Core only. SKILL.md directs dbt Fusion users to the separate cosmos-dbt-fusion skill before implementing Cosmos configuration.
What load mode should large containerized dbt projects use?
cosmos-dbt-core recommends RenderConfig load_method LoadMode.DBT_MANIFEST when projects are large, containerized, or need fastest parsing, provided manifest_path is available.
Is Cosmos Dbt Core safe to install?
skills.sh reports 2 of 3 security scanners passed. Review the Security Audits panel on this page before installing in production.