Package: dbt-airflow
dbt-airflowA Python package that helps Data and Analytics engineers render dbt projects in Apache Airflow DAGs such that
models, seeds, snapshots and tests are represented by individual Airflow Task.dbtis a command-line tool that enables data teams build, maintain and test data models in a scalable fashion. The
biggest challenge though is how to embeddbtin modern data workflows and infrastructure. dbt CLI is indeed a powerful
tool, but if used as is, it will create silos in the way an organisation manages its data. Every contributor is able to
rundbtcommands from their local machine (or even a host machine), but how do you know if a model run by another
contributor has failed, or succeeded? How can you enable shared visibility over data models, within the team?One way to host dbt projects and orchestrate dbt tasks is via Apache Airflow. In its simplest form, an Airflow DAG
that will build and test data models will consist of two tasks, one that executesdbt runcommand followed by an
Airflow task that executesdbt test.But what happens when model builds or tests fail? Should we re-run the whole dbt project (that could involve hundreds of
different models and/or tests) just to run a single model we've just fixed? This doesn't seem to be a good practice
since re-running the whole project  will be time-consuming and expensive.A potential solution to this problem is to create individual Airflow tasks for every model, seed, snapshot and test
within the dbt project. If we were about to do this work manually, we would have to put huge effort that would also be
prone to errors. Additionally, it would beat  the purpose of dbt, that among other features, it also automates model
dependency management.dbt-airflowis a package that builds a layer in-between Apache Airflow and dbt, and enables teams to automatically
render their dbt projects in a granular level such that they have full control to individual dbt resource types. Every
dbt model, seed, snapshot or test will have its own Airflow Task so that you can perform any action at a task-level.Here's how the popular Jaffle Shop dbt project will be rendered on Apache Airflow viadbt-airflow:FeaturesRender adbtproject as aTaskGroupconsisting of Airflow Tasks that correspond to dbt models, seeds, snapshots
and testsEverymodel,seedandsnapshotresource that has at least a single test, will also have a corresponding
test task as a downstream taskAdd tasks before or after the whole dbt projectIntroduce extra tasks within the dbt project tasks and specify any downstream or upstream dependenciesCreate sub-TaskGroups of dbt Airflow tasks based on your project's folder structureHow does it workThe library essentially builds on top of the metadata generated bydbt-coreand are stored in
thetarget/manifest.jsonfile in your dbt project directory. This means that you first need to compile (or run
any other dbt command that creates themanifestfile) before creating your Airflow DAG. This means thedbt-airflowpackage expects that you have already compiled your dbt project so that an up to date manifest file can then be used
to render the individual tasks.InstallationThe package is available on PyPI and can be installed throughpip:pipinstalldbt-airflowdbtneeds to connect to your target environment (database, warehouse etc.) and in order to do so, it makes use of
different adapters, each dedicated to a different technology (such as Postgres or BigQuery). Therefore, before runningdbt-airflowyou also need to ensure that the required adapter(s) are installed in your environment.For the full list of available adapters please refer to the officialdbt documentation.UsageBuilding an Airflow DAG usingdbt-airflowfromdatetimeimportdatetime,timedeltafrompathlibimportPathfromairflowimportDAGfromairflow.operators.pythonimportPythonOperatorfromairflow.operators.emptyimportEmptyOperatorfromdbt_airflow.core.configimportDbtAirflowConfig,DbtProjectConfig,DbtProfileConfigfromdbt_airflow.core.task_groupimportDbtTaskGroupfromdbt_airflow.core.taskimportExtraTaskfromdbt_airflow.operators.executionimportExecutionOperatorwithDAG(dag_id='test_dag',start_date=datetime(2021,1,1),catchup=False,tags=['example'],default_args={'owner':'airflow','retries':1,'retry_delay':timedelta(minutes=2),},)asdag:extra_tasks=[ExtraTask(task_id='test_task',operator=PythonOperator,operator_args={'python_callable':lambda:print('Hello world'),},upstream_task_ids={'model.example_dbt_project.int_customers_per_store','model.example_dbt_project.int_revenue_by_date',},),ExtraTask(task_id='another_test_task',operator=PythonOperator,operator_args={'python_callable':lambda:print('Hello world 2!'),},upstream_task_ids={'test.example_dbt_project.int_customers_per_store',},downstream_task_ids={'snapshot.example_dbt_project.int_customers_per_store_snapshot',},),ExtraTask(task_id='test_task_3',operator=PythonOperator,operator_args={'python_callable':lambda:print('Hello world 3!'),},downstream_task_ids={'snapshot.example_dbt_project.int_customers_per_store_snapshot',},upstream_task_ids={'model.example_dbt_project.int_revenue_by_date',},),]t1=EmptyOperator(task_id='dummy_1')t2=EmptyOperator(task_id='dummy_2')tg=DbtTaskGroup(group_id='dbt-company',dbt_project_config=DbtProjectConfig(project_path=Path('/opt/airflow/example_dbt_project/'),manifest_path=Path('/opt/airflow/example_dbt_project/target/manifest.json'),),dbt_profile_config=DbtProfileConfig(profiles_path=Path('/opt/airflow/example_dbt_project/profiles'),target='dev',),dbt_airflow_config=DbtAirflowConfig(extra_tasks=extra_tasks,execution_operator=ExecutionOperator.BASH,test_tasks_operator_kwargs={'retries':0},),)t1>>tg>>t2