Dagster & dbt Fusion
This feature is considered in a preview stage, and is under active development, and not considered ready for production use. You may encounter feature gaps, and the APIs may change. For more information, see the API lifecycle stages documentation.
Run your dbt project on the dbt Fusion engine with Dagster, including how Dagster selects a dbt executable and which features are not supported on Fusion.
The dbt Fusion engine is dbt Labs' rewrite of dbt in Rust. Its main benefit for Dagster users is parse time: Fusion compiles a project's manifest substantially faster than the Python implementation, which is most noticeable on large projects and on every code location reload.
Fusion reached general availability on September 16, 2026. As part of that release, dbt Labs renamed the Fusion engine to dbt and renamed the previous Python implementation to dbt OSS. This page uses "Fusion" and "dbt Core" throughout, since those are the names most existing Dagster projects were built against.
Dagster invokes dbt through the dbt executable, so moving a project to Fusion only requires ensuring the executable your code location resolves is the Fusion executable. There is no feature flag to turn on and nothing to configure in Dagster+.
Requirements
Fusion support landed in the dagster 1.11.5 release. Use dagster-dbt 0.29.12 or later, which ships alongside dagster 1.13.12, to pick up the Fusion fixes released since then.
How Dagster selects a dbt executable
DbtCliResource chooses an executable in this order:
- The
dbt_executableargument, if you set one. - An executable named
dbtfonPATH. - An executable named
dbtonPATH.
Dagster resolves this through PATH in the process that runs your code location.
A few code paths use the absence of dbt-core as the signal that they are running against Fusion. If dbt-core stays installed, those code paths behave as though you were on dbt Core. See Limitations for more information.
Set up a project on Fusion
Install Fusion following the dbt installation documentation.
dagster-dbt does not install dbt Core — it is behind the dagster-dbt[dbt-core] extra. Any dbt adapter package, such as dbt-duckdb or dbt-snowflake, pulls dbt Core in, and its dbt entrypoint can then shadow the Fusion binary. Remove the adapter packages from the environment that runs your code location if you want dbt to resolve to Fusion.
Do not install Fusion's dbt PyPI package into an environment that also has dbt-core. Both distributions own the dbt import namespace and overwrite each other's files, so neither engine ends up working and pip reports no error. If you install Fusion from PyPI, keep dbt-core and every adapter package out of that environment.
Set up your Dagster project to use the dbt Fusion executable by doing one of the following:
Add a dbtf executable to PATH
Adding a dbtf executable to PATH is required to use dbt Fusion with DbtProjectComponent, which constructs its own DbtCliResource and exposes no executable setting.
dbtf is a name Dagster looks for, not one any dbt installer provides, so you create it yourself. The dbt installer does define dbtf, but as a shell alias, and Dagster cannot see a shell alias. Add a real executable or symlink to PATH instead:
ln -s /path/to/fusion/dbt ~/.local/bin/dbtf
Dagster prefers dbtf over dbt, so this selects Fusion regardless of what dbt resolves to. Do this in your image build so it holds for the process that runs your code location.
Set the executable explicitly
If you construct DbtCliResource yourself, you can instead point it at the Fusion binary by absolute path:
from dagster_dbt import DbtCliResource
dbt = DbtCliResource(
project_dir="/path/to/dbt/project",
dbt_executable="/path/to/fusion/dbt",
)
Limitations
Dagster's Fusion support is in preview and has known gaps. Confirm that none of the following block your project before you migrate.
Column metadata needs a dbt-side macro, and row counts are unavailable
fetch_column_metadata() and fetch_row_counts() read the warehouse through dbt Core's adapter, which Fusion does not provide — Dagster skips adapter initialization when the dbt executable reports a 2.x version. On Fusion both methods log a warning and pass dbt events through unchanged, so a pipeline that calls them runs on either engine without failing.
Column schema and column lineage are still available on Fusion through the dagster dbt package's log_column_level_metadata macro, which introspects over the connection dbt already holds rather than one Dagster opens. Add the package to packages.yml or dependencies.yml and run dbt deps:
packages:
- git: 'https://github.com/dagster-io/dagster.git'
subdirectory: 'python_modules/libraries/dagster-dbt/dbt_packages/dagster'
revision: DAGSTER_VERSION # replace with the version of `dagster` you are using.
Then enable the macro as a post-hook on the resources that should emit it:
models:
+post-hook:
- '{{ dagster.log_column_level_metadata() }}'
seeds:
+post-hook:
- '{{ dagster.log_column_level_metadata() }}'
snapshots:
+post-hook:
- '{{ dagster.log_column_level_metadata() }}'
With the hook in place, a plain .stream() attaches dagster/column_schema and dagster/column_lineage; no fetch_column_metadata() call is involved. Note that dagster-dbt logs a deprecation notice for this macro pointing at fetch_column_metadata() — on Fusion, that method cannot work, and the macro is the supported route.
Row counts have no equivalent on Fusion. Track #34227.
Isolated models are dropped from non-default selections
Fusion adds a model to the manifest's child_map only when it has at least one parent, so a model with no ref() or source() calls is absent from the graph Fusion selects against. Dagster works around this in the two cases it can:
| Your environment | Default selection | Non-default select, exclude, or selector |
|---|---|---|
dbt-core installed | Works | Works |
| Fusion only | Works | Isolated models dropped |
With dbt-core installed, Dagster evaluates the selection itself and adds the missing nodes back to the graph. Without it, Dagster reads the default selection straight from the manifest, but any other selection is evaluated by dbt list, which never sees the isolated models.
If you pass a non-default selection on a Fusion-only environment, check your manifest rather than waiting to notice missing assets. Every node in nodes, including seeds and snapshots, should appear in child_map, either as a key or inside one of its lists:
import json
with open("target/manifest.json") as f:
manifest = json.load(f)
child_map = manifest["child_map"]
in_graph = set(child_map) | {child for children in child_map.values() for child in children}
isolated = [unique_id for unique_id in manifest["nodes"] if unique_id not in in_graph]
print(isolated)
Anything this prints is missing from your asset graph. As a workaround, give the model a ref() or source() that is filtered out at runtime, for example with where 1=0. Tracked in #33801.
Open issues
| Issue | Description |
|---|---|
| #33753 | Fusion applies a hardcoded row limit to dbt seed. |
| #34227 | Row counts are unavailable on Fusion, and column metadata requires a dbt-side macro. |
Fusion's own compatibility surface
Fusion has adapter coverage and feature gaps of its own, independent of Dagster. Validate your project against dbt Labs' Fusion upgrade documentation as well.
Verify your setup
From the environment your code location runs in, confirm that dbtf resolves to the Fusion binary. This is the executable Dagster will pick:
which dbtf
dbtf --version
If which dbtf finds nothing, Dagster falls back to dbt, and your models run on whichever engine that resolves to.