<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <id>https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog</id>
    <title>dbt Developer Hub Blog</title>
    <updated>2026-07-23T00:00:00.000Z</updated>
    <generator>https://github.com/jpmonette/feed</generator>
    <link rel="alternate" href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog"/>
    <subtitle>dbt Developer Hub Blog</subtitle>
    <entry>
        <title type="html"><![CDATA[The dbt MCP server comes to Claude: governed context, one sign-in away]]></title>
        <id>https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-mcp-server-claude</id>
        <link href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-mcp-server-claude"/>
        <updated>2026-07-23T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[The governed definitions you build in dbt now flow directly into the workflows where the work actually happens.]]></summary>
        <content type="html"><![CDATA[<p>When we open-sourced the dbt MCP server in <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/introducing-dbt-mcp-server">April 2025</a>, it was an experimental, locally hosted project with a clear thesis behind it: structured data is going to be deeply integrated into AI workflows, and dbt is the layer that provides the governed context those workflows run on. <a href="https://claude.com/blog/how-anthropic-enables-self-service-data-analytics-with-claude" target="_blank" rel="noopener noreferrer">Anthropic</a> has helped validate our thesis. Naturally, it made sense to have a cloud-hosted version with remote OAuth, so you can use it with whatever AI tool you are most comfortable with.</p>
<p>The remote dbt MCP server now runs inside the <span>dbt platform</span>, and you can connect it to Claude in a minute or two by signing in and completing the authentication flow. You add dbt as a connector, approve the access you want, and Claude gains access to your governed data and rich dbt metadata.</p>
<p>This post walks through what the remote server brings to Claude, the types of workflows it fits into for both people and agents, and how the tools compose once they share a conversation.</p>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="the-full-feature-set-at-a-glance">The full feature set at a glance<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-mcp-server-claude#the-full-feature-set-at-a-glance" class="hash-link" aria-label="Direct link to The full feature set at a glance" title="Direct link to The full feature set at a glance">​</a></h2>
<p>The server exposes a set of tools that operate on top of your dbt project. You ask questions in natural language, and Claude selects the right tool for each request. Here are the tools available today. For the complete list, refer to the <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/docs/dbt-ai/mcp-available-tools?version=2.0">available tools documentation</a>.</p>
<div class="filterableTableContainer_mhtg"><table style="display:none"><thead><tr><th>Capability</th><th>What you can ask for</th><th>Representative tools</th></tr></thead><tbody><tr><td>Discovery and lineage</td><td>What models exist, how they connect, what a model contains, and whether it is healthy</td><td><code>get_all_models</code>, <code>get_model_details</code>, <code>get_lineage</code>, <code>get_model_health</code></td></tr><tr><td>Governed metrics</td><td>Business questions answered from your certified Semantic Layer definitions</td><td><code>list_metrics</code>, <code>get_dimensions</code>, <code>query_metrics</code></td></tr><tr><td>Flexible SQL</td><td>Exploratory queries generated and run with full awareness of your models</td><td><code>text_to_sql</code>, <code>execute_sql</code></td></tr><tr><td>Operations</td><td>Job run history, failure details, and retries through the Administrative API</td><td><code>list_jobs_runs</code>, <code>get_job_run_error</code>, <code>retry_job_run</code></td></tr><tr><td>Column lineage</td><td>Dependencies traced to the individual column with the <span>dbt Fusion engine</span></td><td><code>fusion.get_column_lineage</code></td></tr><tr><td>Product docs</td><td>Answers to dbt questions pulled from the official documentation</td><td><code>search_product_docs</code>, <code>get_product_doc_pages</code></td></tr></tbody></table><div class="tableWrapper_oiMt"><div class="searchBar_xnmH"><div class="searchContainer_fLyJ"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M416 208c0 45.9-14.9 88.3-40 122.7L502.6 457.4c12.5 12.5 12.5 32.8 0 45.3s-32.8 12.5-45.3 0L330.7 376c-34.4 25.2-76.8 40-122.7 40C93.1 416 0 322.9 0 208S93.1 0 208 0S416 93.1 416 208zM208 352a144 144 0 1 0 0-288 144 144 0 1 0 0 288z"></path></svg><input type="text" placeholder="Search table..." class="searchInput_xT8h" aria-label="Search table" value=""></div></div><table class="filterableTable_QAKT"><thead><tr></tr></thead><tbody><tr><td colspan="5" style="text-align:center;padding:20px">Loading table...</td></tr></tbody></table></div></div>
<p>The <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/docs/use-dbt-semantic-layer/dbt-sl">dbt Semantic Layer</a> is the anchor of that list and has the greatest potential to unlock value for nontechnical stakeholders. Your metrics are defined explicitly, so when Claude answers a question about revenue or active users, it returns the trusted number. Everything else builds trustworthy context around that governed core, and each tool serves a person asking a question as readily as an agent taking an action.</p>
<p>This quick demo shows how I use the dbt MCP server to understand the capabilities and current state of my data, then answer questions using that context.</p>
<div style="position:relative;max-width:960px;margin:1.5rem auto;padding-bottom:56.25%;height:0;overflow:hidden"><iframe src="https://www.youtube.com/embed/WjlnzTDui2g" title="Demo of the dbt MCP server in Claude" loading="lazy" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen=""></iframe></div>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="composition-of-tools">Composition of tools<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-mcp-server-claude#composition-of-tools" class="hash-link" aria-label="Direct link to Composition of tools" title="Direct link to Composition of tools">​</a></h2>
<link href="/css/featherlight-styles.css" type="text/css" rel="stylesheet"><div class="
          docImage_EYbW
          
          
          
          
        " style="max-width:85%"><span><a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-mcp-server-claude#" data-featherlight="/img/blog/2026-07-23-dbt-mcp-server-claude/tool-time-workflows.jpg"><img data-toggle="lightbox" alt="Tool Time hosts Tim Taylor and Al Borland pointing toward the show's logo" title="The dbt MCP server lets Claude combine governed data with the other tools in your workflow." src="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/img/blog/2026-07-23-dbt-mcp-server-claude/tool-time-workflows.jpg?v=2"></a></span><span class="title_aGrV">The dbt MCP server lets Claude combine governed data with the other tools in your workflow.</span></div>
<p>Almost every process benefits from a trustworthy answer to "What is actually happening in the business?" A campaign plan needs acquisition numbers. A goal needs a baseline. A weekly update needs last week's actuals. Going back to the dashboard is one option, but that context switch is another opportunity to get distracted and takes you out of the decision loop.</p>
<p>Once that governed context from your dbt project is available inside Claude, it becomes the backbone your other connectors build on. Internal knowledge, so-called “context,” project management software, and observability tooling all get sharper when the data beside them is trusted. dbt supplies the keystone; the rest of your work composes around it.</p>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="dbt-context-in-your-everyday-workflows">dbt context in your everyday workflows<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-mcp-server-claude#dbt-context-in-your-everyday-workflows" class="hash-link" aria-label="Direct link to dbt context in your everyday workflows" title="Direct link to dbt context in your everyday workflows">​</a></h2>
<p>The real payoff shows up when you bring dbt's structured data and its context into the workflows you already run. Here are three examples that use dbt project context with other tools.</p>
<h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="1-marketing-campaign-design">1. Marketing campaign design<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-mcp-server-claude#1-marketing-campaign-design" class="hash-link" aria-label="Direct link to 1. Marketing campaign design" title="Direct link to 1. Marketing campaign design">​</a></h3>
<p>In a past life, I was a marketer. As a budding data analyst, I wanted to make as many data-driven decisions as possible. However, the limitations of the tools at the time made proper analysis and planning prohibitive, so I had to rely on taste and experience. Now, you can bring your relevant CRM, paid ads, organic social, and webinar data into a warehouse with governed metrics. You can combine your context, taste, and experience with an analyst that has a command of the data. Trying to weave a story across several dashboards that only go a few levels deep is not a great use of time. Instead, you can get the data you need at the right depth while also focusing on messaging, reaching the audience, and experimentation to drive results.</p>
<h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="2-goal-setting-and-periodic-reviews">2. Goal setting and periodic reviews<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-mcp-server-claude#2-goal-setting-and-periodic-reviews" class="hash-link" aria-label="Direct link to 2. Goal setting and periodic reviews" title="Direct link to 2. Goal setting and periodic reviews">​</a></h3>
<link href="/css/featherlight-styles.css" type="text/css" rel="stylesheet"><div class="
          docImage_EYbW
          
          
          
          
        " style="max-width:85%"><span><a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-mcp-server-claude#" data-featherlight="/img/blog/2026-07-23-dbt-mcp-server-claude/projections-and-goals.jpeg"><img data-toggle="lightbox" alt="A character explaining that projections are hopes and dreams derived from reality" title="Ground projections, goals, and periodic reviews in governed metrics." src="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/img/blog/2026-07-23-dbt-mcp-server-claude/projections-and-goals.jpeg?v=2"></a></span><span class="title_aGrV">Ground projections, goals, and periodic reviews in governed metrics.</span></div>
<p>Targets and recurring updates lean on the same governed metrics, which makes them a natural fit for the server. Set quarterly goals anchored to Semantic Layer baselines, and record them in Google Sheets or Notion. Then, on your preferred cadence, have Claude generate a business review that measures actuals against those targets and post it to a Slack channel. The real unlock is being able to interrogate the numbers and riff with Claude on possible interpretations and strategies. You arrive at the meeting informed, prepared for follow-up questions, and ready with solutions.</p>
<h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="3-data-platform-management">3. Data platform management<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-mcp-server-claude#3-data-platform-management" class="hash-link" aria-label="Direct link to 3. Data platform management" title="Direct link to 3. Data platform management">​</a></h3>
<p>This one is closest to home for analytics engineers. We spend most of our days maintaining the platform, not necessarily building net-new models, and AI is most useful when combined with other data tooling. Use the dbt discovery, model health, lineage, and Administrative API tools alongside an observability connector like Datadog and an incident tool like incident.io. When a job fails or a dashboard looks off, Claude correlates the dbt run error and failing test with infrastructure signals, uses lineage to scope the blast radius, and drafts an incident summary in one place.</p>
<p><em>One more worth trying: safe change management.</em> Before you rename or drop a column, chain <code>fusion.get_column_lineage</code> and <code>get_model_details</code> with your issue tracker in Linear, Jira, or GitHub. Claude traces every downstream model, exposure, and dashboard that depends on the field, then opens tickets or creates a review checklist so the change ships with its full blast radius mapped. I would be remiss if I didn't mention that this is a perfect <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/docs/platform/wizard-overview">Wizard</a> use case.</p>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="getting-started">Getting started<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-mcp-server-claude#getting-started" class="hash-link" aria-label="Direct link to Getting started" title="Direct link to Getting started">​</a></h2>
<p>For detailed setup guidance, refer to <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/docs/dbt-ai/integrate-mcp-claude?version=2.0&amp;name=Fusion">Integrate with Claude</a>.</p>
<ol>
<li>
<p>In the <span>dbt platform</span>, copy your MCP endpoint URL from <strong>Account settings</strong> → <strong>Access URLs</strong> → <strong>MCP Endpoint URL</strong>.</p>
</li>
<li>
<p>In Claude Desktop or the Claude web app, open the connector settings, add a custom connector, paste the URL, and click <strong>Connect</strong>. Claude sends you to dbt to sign in and shows a consent screen where you approve the scopes you want to grant.</p>
</li>
<li>
<p>In Claude Code, add the server to <code>.mcp.json</code> at your project root so your whole team inherits the setup:</p>
<div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#d6deeb;--prism-background-color:#011627"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-json codeBlock_qGQc thin-scrollbar" style="color:#d6deeb;background-color:#011627"><code class="codeBlockLines_p187"><span class="token-line" style="color:#d6deeb"><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token property" style="color:rgb(128, 203, 196)">"mcpServers"</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token property" style="color:rgb(128, 203, 196)">"dbt"</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">      </span><span class="token property" style="color:rgb(128, 203, 196)">"type"</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"http"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">      </span><span class="token property" style="color:rgb(128, 203, 196)">"url"</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"https://YOUR_DBT_HOST_URL/api/ai/v1/mcp/"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
</li>
<li>
<p>Ask a Semantic Layer question like "What was total revenue for the last 30 days, by region?" to confirm the connection.</p>
</li>
</ol>
<p>To use OAuth, you need an account with a static subdomain, which is the <code>abc123</code> in <code>abc123.us1.dbt.com</code>. Availability depends on your plan as remote OAuth rolls out across tiers. Token-based authentication covers clients that don't support OAuth yet. The consent screen is worth reading closely because scopes let you grant Claude exactly the access a workflow needs.</p>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="where-this-is-heading">Where this is heading<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-mcp-server-claude#where-this-is-heading" class="hash-link" aria-label="Direct link to Where this is heading" title="Direct link to Where this is heading">​</a></h2>
<p>In April 2025, we said data teams would increasingly focus on building the rich, governed context that feeds AI systems, and that dbt would become the control plane for that context. The remote server, authenticated and native in Claude, is a step toward turning that vision into reality. The governed definitions you build in dbt now flow directly into everyday workflows, from a marketing brief to an incident review, and both people and agents operate on the same trusted foundation.</p>
<p>This is still early, and the best patterns will come from the community. Grab your MCP endpoint URL, add dbt as a custom connector in Claude, and start with a Semantic Layer question. See how much the tools can accomplish together.</p>
<p>Join the conversation in <code>#tools-dbt-mcp</code> in the dbt community Slack.</p>]]></content>
        <author>
            <name>Alex Noonan</name>
        </author>
        <category label="ai" term="ai"/>
        <category label="data ecosystem" term="data ecosystem"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[No babysitting, not today]]></title>
        <id>https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/wizard-use-cases</id>
        <link href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/wizard-use-cases"/>
        <updated>2026-06-30T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[dbt Wizard is a coding harness purpose built for analytics engineering, Developer experience advocate Alex Noonan uses Wizard to solve a few tricky analytics-problems]]></summary>
        <content type="html"><![CDATA[<p>We recently released <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/docs/platform/wizard-overview">dbt Wizard</a>, a CLI for doing agentic data work on dbt. This is a harness specifically built for data work and as such I was excited to spend an afternoon running dbt Wizard across a personal project with about 100 models or so that I've been maintaining for a while. You can use this project to see firsthand some of the differentiators for Wizard, particularly how the validation loop works.</p>
<p>Data projects are never done and I had a few tasks I've been putting off:</p>
<ul>
<li>Migrating from MotherDuck to Iceberg + BigQuery</li>
<li>Upgrading dbt Core to dbt Fusion</li>
<li>Migrating from dbt Core to dbt platform</li>
<li>Building out a semantic layer</li>
</ul>
<p>These are a good mix of pretty standard data work (have you done your annual migration yet?) and some dbt specific tasks. A good informal eval for the fundamental question for any dev tool: Does it work?</p>
<p>I was pleasantly surprised with my experience in that I didn't have to babysit Wizard or build any additional workflows on top of it. Because it has a native understanding of what a dbt project is, and its ability to set up validation subagents that match the task made it easy for me to just pop in when needed and I didn't have to babysit the whole process and I accomplished all of my objectives.</p>
<link href="/css/featherlight-styles.css" type="text/css" rel="stylesheet"><div class="
          docImage_EYbW
          
          
          
          
        " style="max-width:85%"><span><a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/wizard-use-cases#" data-featherlight="/img/blog/2026-06-25-wizard-use-case/wizard-loop.jpg"><img data-toggle="lightbox" alt="a loop showing how wizard validates changes " title="" src="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/img/blog/2026-06-25-wizard-use-case/wizard-loop.jpg?v=2"></a></span></div>
<p>The repo is public, so you can read the prs that Wizard authored:</p>
<ul>
<li><a href="https://github.com/C00ldudeNoonan/economic-data-project/pull/83" target="_blank" rel="noopener noreferrer">Migrate from MotherDuck to BigQuery + Apache Iceberg</a></li>
<li><a href="https://github.com/C00ldudeNoonan/economic-data-project/pull/98" target="_blank" rel="noopener noreferrer">Prepare dbt Platform and Fusion orchestration</a></li>
<li><a href="https://github.com/C00ldudeNoonan/economic-data-project/pull/102" target="_blank" rel="noopener noreferrer">Fix Semantic Layer for Fusion metric discovery</a></li>
</ul>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="project-background">Project background<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/wizard-use-cases#project-background" class="hash-link" aria-label="Direct link to Project background" title="Direct link to Project background">​</a></h2>
<p>The project is an economic data platform. The Federal Reserve, Bureau of Labor Statistics, Historical stock, ETF commodity prices, and Treasury data come in through Dagster assets, get transformed by dbt, and feed a set of analysis agents. DuckDB and MotherDuck worked fantastically, but I wanted to test out the developer ergonomics and cost of Iceberg, and the <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/docs/fusion/about-fusion">dbt Fusion engine</a>.</p>
<p>The primary interface that I use to consume this data is via a Claude plugin where I ask questions about market state, where we are in the economic cycle, running backtests, that type of thing. It helps me test new investment and trade ideas and going back and forth with an AI is pretty ergonomic for this type of thing. I had some issues with data quality in the <a href="https://noonanlabs.substack.com/p/so-i-looked-at-the-data" target="_blank" rel="noopener noreferrer">past</a> so improving accuracy and repeatability is important. I also had Wizard build out the initial <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/docs/use-dbt-semantic-layer/dbt-sl">Semantic Layer</a> and metrics.</p>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="the-validation-loop-in-practice">The Validation loop in practice<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/wizard-use-cases#the-validation-loop-in-practice" class="hash-link" aria-label="Direct link to The Validation loop in practice" title="Direct link to The Validation loop in practice">​</a></h2>
<p>Wizard has this built-in <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/docs/dbt-ai/wizard-how-it-works#validation-loop-mechanics">validation loop</a> that starts with the intended change, implements the most reasonable version, checks to see if it works in the project, if validation fails or exposes a mismatch, Wizard adjusts the implementation.</p>
<p>A common metric that I look at when thinking about the financial market is volatility or price variance. Being able to normalize across nominal prices is necessary so you can do a true apples to apples comparison. The calculation works like this:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#d6deeb;--prism-background-color:#011627"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-text codeBlock_qGQc thin-scrollbar" style="color:#d6deeb;background-color:#011627"><code class="codeBlockLines_p187"><span class="token-line" style="color:#d6deeb"><span class="token plain">V = σ_1yr / P_current</span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">where:</span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">  σ_1yr     = trailing one-year standard deviation of the price</span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">  P_current = the latest close</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Take the one-year standard deviation of a price, divide by the current price, and you get a dimensionless volatility proxy you can compare across assets at wildly different price levels.</p>
<div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#d6deeb;--prism-background-color:#011627"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-yaml codeBlock_qGQc thin-scrollbar" style="color:#d6deeb;background-color:#011627"><code class="codeBlockLines_p187"><span class="token-line" style="color:#d6deeb"><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain"> </span><span class="token key atrule" style="color:rgb(255, 203, 139)">name</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> annualized_volatility_ratio</span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token key atrule" style="color:rgb(255, 203, 139)">type</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> ratio</span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token key atrule" style="color:rgb(255, 203, 139)">type_params</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token key atrule" style="color:rgb(255, 203, 139)">numerator</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">      </span><span class="token key atrule" style="color:rgb(255, 203, 139)">name</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> price_volatility_proxy</span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token key atrule" style="color:rgb(255, 203, 139)">denominator</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">      </span><span class="token key atrule" style="color:rgb(255, 203, 139)">name</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> max_close_price</span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>This was Wizard’s first attempt, pretty simple. It failed during the validation loop because it had two modeling problems:</p>
<ol>
<li><code>Max_close_price</code> was not quite the expression I wanted, current\last_price was what I needed, not the max close over a current window.</li>
<li>It depended on cross-metric references in metrics.yml, which became fragile once Wizard migrated metrics inline to be in support of fusion.</li>
</ol>
<p>For validation Wizard had to work within the following constraints:</p>
<p>- Fusion needed to discover metrics colocated with model YAML.<br>
<!-- -->- dbt Core/Dagster needed to parse the project without choking on newer semantic syntax. (I ended up fixing this <a href="https://github.com/C00ldudeNoonan/economic-data-project/pull/100" target="_blank" rel="noopener noreferrer">later</a> to be Fusion across the board but it was a fun challenge to see Wizard deal with)<br>
<!-- -->- CI needed a stable project parse/build path.<br>
<!-- -->- dbt Platform needed deployed artifacts that the hosted Semantic Layer could actually expose.</p>
<p>Wizard tried again with an older MetricFlow-style shape. Which was suboptimal in that it worked for one parser but didn't work for another.</p>
<p>Better for one parser, worse for the other. It flipped which side failed, which is the kind of result that eats an afternoon when you do it by hand.</p>
<p>The version that shipped is the least clever of the three but it worked.</p>
<div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#d6deeb;--prism-background-color:#011627"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-yaml codeBlock_qGQc thin-scrollbar" style="color:#d6deeb;background-color:#011627"><code class="codeBlockLines_p187"><span class="token-line" style="color:#d6deeb"><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain"> </span><span class="token key atrule" style="color:rgb(255, 203, 139)">name</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> annualized_volatility_ratio</span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token key atrule" style="color:rgb(255, 203, 139)">label</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> Annualized Volatility Ratio</span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token key atrule" style="color:rgb(255, 203, 139)">description</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> Average ratio of 1</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">year price StdDev to close price</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> a dimensionless proxy for annualized volatility. Higher means more volatile relative to price level.</span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token key atrule" style="color:rgb(255, 203, 139)">type</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> simple</span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token key atrule" style="color:rgb(255, 203, 139)">agg</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> average</span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token key atrule" style="color:rgb(255, 203, 139)">expr</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> std_diff_1yr / nullif(current_price</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> 0)</span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>The ratio logic moved into the expr, the nullif kills the divide-by-zero, and it parses under Fusion, parses under dbt Core, and passes the project CI. Having Wizard do the validation loop to understand the finer points in the differences between dbt Core and Fusion saved me a ton of time.</p>
<p>For this process, I didn't have to look up any documentation and only had to go back and forth with Wizard a few times, mostly for my understanding. This was a success for me since I now have a simple metric, that matches the expected formula, and has both parser compatibility and a hosted semantic layer deployment path. I also only had to see on diff, which was the final one, the dead ends and iterations happened off screen so I only needed to be tapped in when necessary.</p>
<link href="/css/featherlight-styles.css" type="text/css" rel="stylesheet"><div class="
          docImage_EYbW
          
          
          
          
        " style="max-width:85%"><span><a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/wizard-use-cases#" data-featherlight="/img/blog/2026-06-25-wizard-use-case/mcp-validation.png"><img data-toggle="lightbox" alt="claude result of querying the mcp for the annualized volatility ratio metric from the semantic layer " title="" src="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/img/blog/2026-06-25-wizard-use-case/mcp-validation.png?v=2"></a></span></div>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="why-it-could-run-unattended">Why it could run unattended<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/wizard-use-cases#why-it-could-run-unattended" class="hash-link" aria-label="Direct link to Why it could run unattended" title="Direct link to Why it could run unattended">​</a></h2>
<p>Three things made that work, some of them can be replicated with other harnesses using skills, MCPs, hooks and other automation but these came out of the box.</p>
<p><strong>It knew the graph before it started.</strong> Wizard has a <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/docs/dbt-ai/wizard-how-it-works#native-metadata-engine">native metadata engine</a>, a structured index of lineage, models, tests, and metric definitions, built before the first prompt. When it wrote <code>std_diff_1yr</code> and <code>current_price</code> into that <code>expr</code>, it didn't have to grep through the sql files to find the right name it was able to quickly know what field was the right ones.</p>
<p><strong>Validation was the default.</strong> I never said "check that it compiles." The loop runs on write operations whether you ask or not. You can turn this feature off if it isn't interesting to you.</p>
<p><strong>It stayed in its sandbox.</strong> The task was building out an initial set of metrics in the markets domain. It didn't wander off to refactor unrelated models or rewrite my Dagster assets. It scoped the change, iterated inside that scope, and surfaced a diff for review. Nothing persisted without my approval. This tight scope is what makes "look away and come back" a safe move instead of having a tech debt super spreader event.</p>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="the-proof-i-wanted">The proof I wanted<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/wizard-use-cases#the-proof-i-wanted" class="hash-link" aria-label="Direct link to The proof I wanted" title="Direct link to The proof I wanted">​</a></h2>
<p>A green compile is not proof a Semantic Layer change works. It tells you the YAML is shaped right, not that a metric is discoverable and queryable against your real warehouse. So after the PR merged and the dbt platform jobs ran, I checked the hosted layer directly: dialect BIGQUERY, 43 metrics discovered, query status SUCCESSFUL. Then I ran an actual metric query through the dbt MCP and got real numbers back from BigQuery.</p>
<p>But the biggest proof for me is that I was able to give Wizard a defined set of analytics tasks before a string of meetings and it just went through and completed them without any major interventions on my end. The best part was at the end of it everything worked and during those meetings I was able to be present and contribute without being tempted to make sure my agent wasn't going off the rails. Maybe the real evals were the friends we made along the way.</p>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="other-things-it-did-well">Other things it did well<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/wizard-use-cases#other-things-it-did-well" class="hash-link" aria-label="Direct link to Other things it did well" title="Direct link to Other things it did well">​</a></h2>
<p>A few shorter wins from the same stretch of work:</p>
<ul>
<li><strong>It refused to chase a misleading error.</strong> A local command threw a Snowflake auth error in a BigQuery project. Wizard separated the hosted environment (correctly BigQuery) from a stale Snowflake credential path on my laptop. That reframed the fix from "production is broken" to "your local creds are stale," which is the difference between an hour and a day.</li>
<li><strong>It knew "merged" and "available" are different states.</strong> A merged PR doesn't mean the Semantic Layer refreshed. Wizard traced the gap to dbt platform job execution, ran the deploy jobs, then confirmed the metrics were live.</li>
<li><strong>It colocated the definitions.</strong> The metrics started scattered across standalone files. Wizard moved them into model-owned <code>schema.yml</code>, so each metric sits next to the columns it measures. The Semantic Layer stopped being a metadata island.</li>
<li><strong>It made a pragmatic cut.</strong> Some saved queries were brittle against the migrated metrics. Rather than block the change, it pulled them out, shipped stable metric discovery first, and left them as follow-up. I'd have fought them for an hour. Cutting was right.</li>
</ul>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="try-it">Try it<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/wizard-use-cases#try-it" class="hash-link" aria-label="Direct link to Try it" title="Direct link to Try it">​</a></h2>
<p>The <a href="https://github.com/C00ldudeNoonan/economic-data-project" target="_blank" rel="noopener noreferrer">repo</a> is public if you are curious about the actual metrics and the merged PRs:. Install the Wizard CLI and point it at a project that runs Fusion or dbt Core:</p>
<div class="language-shell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#d6deeb;--prism-background-color:#011627"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-shell codeBlock_qGQc thin-scrollbar" style="color:#d6deeb;background-color:#011627"><code class="codeBlockLines_p187"><span class="token-line" style="color:#d6deeb"><span class="token function" style="color:rgb(130, 170, 255)">curl</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(214, 222, 235)">-fsSL</span><span class="token plain"> https://public.cdn.getdbt.com/dbt-wizard/install/install-wizard.sh </span><span class="token operator" style="color:rgb(127, 219, 202)">|</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">sh</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>The <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/docs/platform/wizard-overview">Wizard docs</a> cover setup, and <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/docs/dbt-ai/wizard-how-it-works">how it works</a> goes deeper on the validation loop. If you try it on a migration of your own, come tell me in <code>#dbt-wizard</code> in the <a href="https://www.getdbt.com/community/join-the-community" target="_blank" rel="noopener noreferrer">dbt Community Slack</a>.</p>]]></content>
        <author>
            <name>Alex Noonan</name>
        </author>
        <category label="analytics craft" term="analytics craft"/>
        <category label="ai" term="ai"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[How dbt State actually works to save your compute costs]]></title>
        <id>https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/how-dbt-state-works</id>
        <link href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/how-dbt-state-works"/>
        <updated>2026-06-25T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[dbt State reuses any model it can prove hasn't meaningfully changed — and unlike its predecessor, it works in dbt Core, in development, and in CI.]]></summary>
        <content type="html"><![CDATA[<p>When building a dbt project, you start with the simplest strategy and only add complexity when you need more speed or reduced cost. At a model-by-model level, this is the view → table → incremental materialization pattern. At a project-wide level, optimizations used to require a lot more complexity - rebuilding only the relevant parts of a project meant you spent a lot of mental energy chaining together selectors like <code>state:modified</code>, <code>source_status:fresher</code>, or <code>config.materialized:view</code> and ensuring fresh JSON artifacts were distributed across your organization.</p>
<p>dbt State provides more speed, reduced cost, and less complexity all in one. It works wherever you do: dbt Core or Fusion, locally or on any orchestrator you choose. Since it's backed by a new paid service (with a 30 day free trial), you don't need to adopt the whole dbt platform to get these savings. dbt State supersedes state-aware orchestration, which required a dbt platform subscription and moving to Fusion.</p>
<p>The most technically interesting part of this is the query normalization process<sup><a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/how-dbt-state-works#user-content-fn-1-1c4d16" id="user-content-fnref-1-1c4d16" data-footnote-ref="true" aria-describedby="footnote-label">1</a></sup> which means running the new <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/reference/commands/lint"><code>dbt lint</code> command</a> doesn't instantly sign you up for a full rebuild. But before getting into the depths of syntax trees, let's recap what dbt State actually does for an end user.</p>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="the-basic-dbt-state-workflow">The basic dbt State workflow<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/how-dbt-state-works#the-basic-dbt-state-workflow" class="hash-link" aria-label="Direct link to The basic dbt State workflow" title="Direct link to The basic dbt State workflow">​</a></h2>
<p>When dbt runs, it will check with the dbt State server whether a model:</p>
<ul>
<li>already exists in the target schema and can be reused</li>
<li>already exists in another schema and can be reused, or</li>
<li>needs to be built from scratch.</li>
</ul>
<h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="reuse-equivalent-objects">Reuse equivalent objects<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/how-dbt-state-works#reuse-equivalent-objects" class="hash-link" aria-label="Direct link to Reuse equivalent objects" title="Direct link to Reuse equivalent objects">​</a></h3>
<p>In this example, a <code>dbt build</code> in the empty dev_joel environment will <strong>clone all provably unchanged objects</strong> from another environment that contains equivalent data, and will also reuse the test results for those nodes.</p>
<figure><video width="100%" controls="" autoplay="" muted="" loop=""><source src="/img/blog/2026-06-17-how-dbt-state-works/reuse-clone-unchanged-objects.mp4" type="video/mp4"></video><figcaption style="text-align:center;font-size:small">In an empty schema, dbt State will clone objects from production and reuse the test results.</figcaption></figure>
<h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="skip-unimportant-modifications">Skip unimportant modifications<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/how-dbt-state-works#skip-unimportant-modifications" class="hash-link" aria-label="Direct link to Skip unimportant modifications" title="Direct link to Skip unimportant modifications">​</a></h3>
<p>“Provably unchanged” doesn't necessarily mean the file is exactly the same as before. dbt State’s SQL comprehension will ignore unimportant modifications like adding a comment or updating whitespace (for example, if you run <code>dbt lint --fix</code>).</p>
<figure><video width="100%" controls="" autoplay="" muted="" loop=""><source src="/img/blog/2026-06-17-how-dbt-state-works/skip-cosmetic-sql-changes.mp4" type="video/mp4"></video><figcaption style="text-align:center;font-size:small">Linting doesn't change the logic of the query, so the existing objects can be reused.</figcaption></figure>
<h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="targeted-rebuilds">Targeted rebuilds<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/how-dbt-state-works#targeted-rebuilds" class="hash-link" aria-label="Direct link to Targeted rebuilds" title="Direct link to Targeted rebuilds">​</a></h3>
<p>When a file does change (or an upstream parent changes/gets new data), it will be rebuilt as you’d expect. But unlike <code>state:modified+</code>, downstream models can be skipped if dbt State determines they don't depend on that change. In this example, the <code>customers</code> view specifies the exact columns it uses, so adding a new column to <code>orders</code> doesn't cause an unnecessary rebuild.</p>
<figure><video width="100%" controls="" autoplay="" muted="" loop=""><source src="/img/blog/2026-06-17-how-dbt-state-works/targeted-rebuild-orders.mp4" type="video/mp4"></video><figcaption style="text-align:center;font-size:small">After adding a new column and a test to the orders model, it is rebuilt and re-tested. The customers view is left alone.</figcaption></figure>
<h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="reuse-from-any-matching-schema">Reuse from any matching schema<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/how-dbt-state-works#reuse-from-any-matching-schema" class="hash-link" aria-label="Direct link to Reuse from any matching schema" title="Direct link to Reuse from any matching schema">​</a></h3>
<p>dbt State will cast a wide net when trying to reuse objects. If Toby checks out an in-progress branch and builds the same model, he’ll clone the dev table instead of rebuilding it from scratch, even though it hasn’t been built in production yet. One extra thing to note: the new test's definition is wrong, so it's failing. Even though the test isn’t being re-executed, its warning still appears.</p>
<figure><video width="100%" controls="" autoplay="" muted="" loop=""><source src="/img/blog/2026-06-17-how-dbt-state-works/reuse-clone-from-any-schema.mp4" type="video/mp4"></video><figcaption style="text-align:center;font-size:small">dbt State finds the right version of an object, wherever it is. Failing tests are surfaced without being re-executed.</figcaption></figure>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="a-deeper-dive">A deeper dive<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/how-dbt-state-works#a-deeper-dive" class="hash-link" aria-label="Direct link to A deeper dive" title="Direct link to A deeper dive">​</a></h2>
<p>Let's go a bit deeper into how dbt State decides what to do with each node in the DAG. The three big questions are:</p>
<ul>
<li>Is there a logic change in the node or any of its parents?</li>
<li>Is there fresh data that exceeds the configured <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/reference/resource-configs/lag-tolerance"><code>lag_tolerance</code></a>?</li>
<li>Is there a config change in the node?</li>
</ul>
<h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="query-normalization">Query normalization<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/how-dbt-state-works#query-normalization" class="hash-link" aria-label="Direct link to Query normalization" title="Direct link to Query normalization">​</a></h3>
<p>dbt’s normal <code>state:modified</code> selector hashes the contents of a file. dbt State is better because it <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/sql-comprehension-technologies#level-1-parsing">parses the query into a syntax tree</a>, and then calculates a hash of the query. This means it won’t rebuild on a syntactically equivalent change, like removing whitespace, adding a comment, or changing a table’s alias.</p>
<link href="/css/featherlight-styles.css" type="text/css" rel="stylesheet"><div class="
          docImage_EYbW
          
          
          
          
        " style="max-width:100%"><span><a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/how-dbt-state-works#" data-featherlight="/img/blog/2026-06-17-how-dbt-state-works/query-normalisation-hash-comparison.png"><img data-toggle="lightbox" alt="Two semantically equivalent SQL files produce different file hashes without dbt State, but normalizing each into a syntax tree yields the same comparison hash with dbt State" title="dbt State considers queries to be equivalent despite cosmetic differences" src="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/img/blog/2026-06-17-how-dbt-state-works/query-normalisation-hash-comparison.png?v=2"></a></span><span class="title_aGrV">dbt State considers queries to be equivalent despite cosmetic differences</span></div>
<p>The purpose of this normalization is to ensure that your model only gets rebuilt when its logic or data changes. One wrinkle in this is volatile SQL functions, like <code>current_timestamp()</code> or <code>random()</code>. Are they logic, like every other piece of code? Or are they themselves data, and when they change the model is invalidated and should be rebuilt?</p>
<p>By default, volatile SQL is treated as logic. The hash is based on the function’s name, not the value it returns. Normally this is the right choice - otherwise every model using <code>getdate()</code> (and every one of its descendants) would be ineligible for reuse ever! But if you have a model where the hash should change when the function’s result changes, you have two options:</p>
<ol>
<li>Use a Jinja function instead - parsing and normalization happens after the Jinja has been rendered, so <code>{{ modules.datetime.datetime.now() }}</code> will cause a different result each time</li>
<li>Set the <code>evaluate_volatile_sql</code> config in your model to true.</li>
</ol>
<p>Of those options, setting the config is normally the better choice (it applies to all functions in the model at once, and can be inherited like any other config). When enabled, dbt State will emulate the function’s value and embed it into the hash of the SQL.</p>
<video width="100%" controls="" autoplay="" muted="" loop=""><source src="/img/blog/2026-06-17-how-dbt-state-works/volatile-sql-hash.mp4" type="video/mp4"></video>
<h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="freshness-checks">Freshness checks<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/how-dbt-state-works#freshness-checks" class="hash-link" aria-label="Direct link to Freshness checks" title="Direct link to Freshness checks">​</a></h3>
<p>dbt State fetches the last modified time for each <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/reference/dbt-classes#relation">Relation</a> in the query. It defaults to using the warehouse's metadata for efficiency, but you can also specify a <code>loaded_at_field</code>/<code>loaded_at_query</code>.</p>
<p>If any of the input Relations are views without a <code>loaded_at_field</code>/<code>loaded_at_query</code> specified, then State will traverse further upstream until it finds a real table and will use that timestamp.</p>
<p>It sends the freshness information and the query text to the dbt State server to decide whether and how it can be reused (the query text is discarded after the server finishes its work).</p>
<h4 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="lag_tolerance">lag_tolerance<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/how-dbt-state-works#lag_tolerance" class="hash-link" aria-label="Direct link to lag_tolerance" title="Direct link to lag_tolerance">​</a></h4>
<p>In a development environment, you probably don't need to re-clone from elsewhere every time fresh data lands. As fast and cheap as it is to clone a model compared to building it from scratch, it's faster and cheaper to do nothing at all.</p>
<p>Put another way, there's a certain amount of <em>lag</em> you're willing to <em>tolerate</em>, and it's different for different environments. You can express that <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/reference/resource-configs/lag-tolerance"><code>lag_tolerance</code></a> as an environment-specific model config:</p>
<div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#d6deeb;--prism-background-color:#011627"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-yaml codeBlock_qGQc thin-scrollbar" style="color:#d6deeb;background-color:#011627"><code class="codeBlockLines_p187"><span class="token-line" style="color:#d6deeb"><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># dbt_project.yml</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token key atrule" style="color:rgb(255, 203, 139)">models</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token key atrule" style="color:rgb(255, 203, 139)">+state</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token key atrule" style="color:rgb(255, 203, 139)">lag_tolerance</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"{{ '4h' if target.name == 'prod' else '7d' }}"</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>By doing that, dbt State won’t consider cloning models until there’s fresh data elsewhere, <em>and</em> the current data is 7 days old. A model inside its lag tolerance window will still be counted as a DATT if you select it for execution and it can be reused, so we recommend continuing to use selectors in development.</p>
<h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="configuration-changes">Configuration changes<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/how-dbt-state-works#configuration-changes" class="hash-link" aria-label="Direct link to Configuration changes" title="Direct link to Configuration changes">​</a></h3>
<p>Some configs on a model don’t change anything about it in the database, like <code>meta</code> or <code>tags</code>. Others, like <code>on_schema_change</code>, <code>severity</code> or <code>materialization</code> directly impact the way your model is built when changed. dbt State will only pay attention to the subset of relevant configs. If you have a custom post-hook which updates your tables based on ignored fields (<a href="https://github.com/Montreal-Analytics/dbt-snowflake-utils#snowflake_utilsapply_meta_as_tags-source" target="_blank" rel="noopener noreferrer">like this</a>), set <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/reference/resource-configs/execute-hooks-on-any-reuse"><code>execute_hooks_on_any_reuse</code></a> to true.</p>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="tips-for-setting-up-dbt-state">Tips for setting up dbt State<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/how-dbt-state-works#tips-for-setting-up-dbt-state" class="hash-link" aria-label="Direct link to Tips for setting up dbt State" title="Direct link to Tips for setting up dbt State">​</a></h2>
<h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="enforce-usage-across-your-team">Enforce usage across your team<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/how-dbt-state-works#enforce-usage-across-your-team" class="hash-link" aria-label="Direct link to Enforce usage across your team" title="Direct link to Enforce usage across your team">​</a></h3>
<p>The more people on your team who reuse models thanks to dbt State, the more benefit you'll see compared to them building those models from scratch every time.</p>
<p>At the beginning, we normally see one or two power users in a team take dbt State for a spin. During that experimentation phase, use the <code>--manage-state</code> flag, <code>DBT_ENGINE_MANAGE_STATE</code> environment variable or <code>~/.dbt/user_settings.yml</code> file to turn State on for just yourself (this will happen automatically when you run <code>dbt login</code>).</p>
<p>When you're ready to deploy it more broadly, update your <code>dbt_project.yml</code> file and commit it to source control. Your colleagues on a modern version of dbt will be prompted to log in next time they invoke dbt. Remember that versions 1.11 and lower need to explicitly <code>pip install dbt-state</code> first.</p>
<div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#d6deeb;--prism-background-color:#011627"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-yaml codeBlock_qGQc thin-scrollbar" style="color:#d6deeb;background-color:#011627"><code class="codeBlockLines_p187"><span class="token-line" style="color:#d6deeb"><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># dbt_project.yml</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token key atrule" style="color:rgb(255, 203, 139)">flags</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token key atrule" style="color:rgb(255, 203, 139)">manage_state</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token boolean important" style="color:rgb(255, 88, 116)">true</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="shape-the-development-of-dbt-state">Shape the development of dbt State<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/how-dbt-state-works#shape-the-development-of-dbt-state" class="hash-link" aria-label="Direct link to Shape the development of dbt State" title="Direct link to Shape the development of dbt State">​</a></h2>
<p>Using dbt State feels very familiar to the normal way of developing with dbt, but it's also a new way of thinking. The best way to start is by following the <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/docs/deploy/dbt-state-setup">dbt State setup</a> guide. After that, if you want to talk about how it's going, share feedback or ask questions, come and find us in <a href="https://www.getdbt.com/community/join-the-community" target="_blank" rel="noopener noreferrer"><code>#dbt-state</code> on Slack</a>.</p>
<!-- -->
<section data-footnotes="true" class="footnotes"><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5 sr-only" id="footnote-label">Footnotes<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/how-dbt-state-works#footnote-label" class="hash-link" aria-label="Direct link to Footnotes" title="Direct link to Footnotes">​</a></h2>
<ol>
<li id="user-content-fn-1-1c4d16">
<p>The second-most interesting part is the pair of bylines on this post. Welcome to the Developer Blog, Toby! <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/how-dbt-state-works#user-content-fnref-1-1c4d16" data-footnote-backref="" aria-label="Back to reference 1" class="data-footnote-backref">↩</a></p>
</li>
</ol>
</section>]]></content>
        <author>
            <name>Joel Labes</name>
        </author>
        <author>
            <name>Toby Mao</name>
        </author>
        <category label="analytics craft" term="analytics craft"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[dbt Core v2 is here: still open source, now rebuilt for what's next]]></title>
        <id>https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-core-v2-is-here</id>
        <link href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-core-v2-is-here"/>
        <updated>2026-06-01T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[The two-engine era is drawing to a close: from now on, dbt Core and Fusion will be built on a shared foundation.]]></summary>
        <content type="html"><![CDATA[<p>Today, we published the <strong>first alpha release of dbt Core version 2.0</strong>, raising the baseline for what dbt users can expect from their transformation tool. As always, dbt Core's code is completely open source under the Apache 2.0 license. What makes this release significant is that dbt Core 2.0 is now built on the same foundations as the <a href="https://www.getdbt.com/product/fusion" target="_blank" rel="noopener noreferrer">dbt Fusion engine</a> – we've open-sourced a lot of Fusion code for the first time.</p>
<p>The launch of dbt Core 2.0 comes with key feature developments:</p>
<ul>
<li><strong>Significant parse time improvements</strong>, especially on the largest dbt projects</li>
<li><strong>A tightly-defined language spec</strong> which makes it impossible to accidentally configure a <code>desciptin</code> instead of a <code>description</code>, and gives anyone integrating with the dbt ecosystem (including dbt's own development team!) a stable interface to build against.</li>
<li><strong>New Parquet artifacts</strong> as a high-performance alternative to large JSON files that can be directly queried through DuckDB or your <a href="https://www.getdbt.com/product/dbt-wizard" target="_blank" rel="noopener noreferrer">agent of choice</a></li>
<li><strong>A completely revamped local documentation experience,</strong> powered by those new artifacts and capable of scaling to projects of arbitrary size.</li>
<li><strong>A more streamlined way to build new adapters</strong>, powered by ADBC and the Arrow ecosystem</li>
<li><strong>A simplified installation process</strong> that removes the need to fight with Python's virtual environments</li>
</ul>
<p>If you've been an early adopter of the dbt Fusion engine, these features might sound familiar. That's because the two-engine era is drawing to a close: from now on, dbt Core and Fusion will be built on a shared foundation. The subset of code (we're calling it the runtime) which we <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-fusion-engine-components#source-available-dbt-fusion-engine">previously committed to releasing publicly under the ELv2 license</a> is now under the Apache 2.0 license as dbt Core. Fusion will continue to extend that baseline by adding advanced capabilities - some are totally free to use, and other premium features are unlocked with a free login or payment method.</p>
<p>We think that this is the best way to continue to meet our commitments as stewards of the dbt framework, the best way to enable <a href="https://roundup.getdbt.com/p/one-dbt" target="_blank" rel="noopener noreferrer">our <em>One dbt</em> vision</a>, and the best way to maintain dbt's position as the standard for data transformation in the agentic era.</p>
<p>If you want to learn more about the new capabilities in dbt Core and where we're headed next, Jeremy, Elias, and I (Grace) <a href="https://github.com/dbt-labs/dbt-core/blob/main/docs/roadmap/2026-06-announcing-v2.md" target="_blank" rel="noopener noreferrer">just published another roadmap post</a> - go check it out. For more detail about what is (and isn't) changing, and why we're doing this, read the rest of this post.</p>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="putting-all-our-efforts-behind-a-single-engine">Putting all our efforts behind a single engine<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-core-v2-is-here#putting-all-our-efforts-behind-a-single-engine" class="hash-link" aria-label="Direct link to Putting all our efforts behind a single engine" title="Direct link to Putting all our efforts behind a single engine">​</a></h2>
<p>When deciding how to release the dbt Fusion engine last year, we were faced with a set of strict requirements. Tristan <a href="https://www.getdbt.com/blog/new-code-new-license-understanding-the-new-license-for-the-dbt-fusion-engine" target="_blank" rel="noopener noreferrer">described them in detail</a> at the time, and you'll see them in the table below. The result was that we chose to build the new Fusion engine separately from Core, and under a different license (ELv2).</p>
<p>This worked well enough during Fusion's development period: new language features like Iceberg catalog support, <code>--sample</code>, and UDF definitions got equivalent OSS implementations in dbt Core v1.10 and v1.11.</p>
<p>But as Fusion's GA approaches, it's clear that its underlying technologies (like Rust, ADBC, and Parquet) are much better suited for future innovation. We want those technologies to be the foundation we can build on for <strong>everyone</strong>.</p>
<p>Revisit the same list of goals with one extra requirement – no bifurcated engine – and it comes out looking like this:</p>
<link href="/css/featherlight-styles.css" type="text/css" rel="stylesheet"><div class="
          docImage_EYbW
          
          
          
          
        " style="max-width:100%"><span><a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-core-v2-is-here#" data-featherlight="/img/blog/2026-06-01-dbt-core-v2-is-here/licensing-decisions-2025-vs-2026.png"><img data-toggle="lightbox" alt="Side-by-side table comparing the original 2025 licensing decisions to the new decisions for each goal: broader adoption (including via other dbt-as-a-service platforms), commercial protection without blocking premium opt-in, and a dbt Core becoming the shared runtime code from the dbt Fusion engine." title="" src="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/img/blog/2026-06-01-dbt-core-v2-is-here/licensing-decisions-2025-vs-2026.png?v=2"></a></span></div>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="better-defining-dbt-cores-role-in-the-ecosystem">Better defining dbt Core's role in the ecosystem<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-core-v2-is-here#better-defining-dbt-cores-role-in-the-ecosystem" class="hash-link" aria-label="Direct link to Better defining dbt Core's role in the ecosystem" title="Direct link to Better defining dbt Core's role in the ecosystem">​</a></h2>
<p>As we introduced the different variants of the dbt Fusion engine last year, we <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-fusion-engine-components#ways-to-access">explained</a> that to distribute a Python program you have to distribute its underlying source code.</p>
<p>Historically, this has caused dbt Core to also be conflated with "<em>the one you can use for free</em>," or "<em>the one you can use on your laptop</em>," because the only way to provide a free, locally-installable version of dbt was for its Python code to be 100% open source. This meant the majority of dbt users missed out on useful capabilities whose implementation details we couldn't share.</p>
<p>By contrast, Rust projects can be distributed as binaries without disclosing any proprietary source code. This is why we're able to put out multiple free distributions of the v2 engine: one called Fusion providing the best experience in a binary containing some proprietary code, and another made up entirely of the Apache 2 open source code in the <code>dbt-core</code> repo.</p>
<p>Which v2 distribution should you choose for your use case? Almost certainly Fusion. Put another way: <strong>For the best free dbt CLI you can use locally and in production environments, install Fusion</strong>. It can do more than dbt Core out of the box and you can seamlessly enable other premium features over time if you choose to. Changes contributed to the dbt-core repository will be applied to Fusion. We also know that there is a small subset of teams who are required to use dbt Core today because of its license, or who are building custom things on top of the OSS code. If you find yourself in one of those camps (you'll know), we see you, and dbt Core v2.0 is here for you.</p>
<p>Regardless of the distribution you choose, it's still a single framework with a single language specification. Your critical business logic is portable in both directions.</p>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="who-benefits-from-these-changes">Who benefits from these changes?<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-core-v2-is-here#who-benefits-from-these-changes" class="hash-link" aria-label="Direct link to Who benefits from these changes?" title="Direct link to Who benefits from these changes?">​</a></h2>
<p>We think this is great for everyone in the dbt ecosystem, and a significant improvement over the status quo.</p>
<ul>
<li>We are open-sourcing a huge amount of IP, for anyone to use however they see fit.</li>
<li>The enhanced Fusion binary is now available for use everywhere (including to power products competing with Fivetran + dbt Labs) with a <a href="https://www.getdbt.com/licenses-faq" target="_blank" rel="noopener noreferrer">more permissive license</a>.</li>
<li>Setting a clear roadmap encourages widespread adoption of v2 of the dbt framework, which in turn makes it easier for integrations to build against a common set of functionality.</li>
<li>A shared runtime between the open source and proprietary distributions of dbt ensures that OSS users benefit directly from our ongoing investment in dbt, instead of trusting that features will be ported from Rust to Python on an ongoing basis.</li>
</ul>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="recap-whats-changing-whats-staying-the-same">Recap: what's changing, what's staying the same<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-core-v2-is-here#recap-whats-changing-whats-staying-the-same" class="hash-link" aria-label="Direct link to Recap: what's changing, what's staying the same" title="Direct link to Recap: what's changing, what's staying the same">​</a></h2>
<link href="/css/featherlight-styles.css" type="text/css" rel="stylesheet"><div class="
          docImage_EYbW
          
          
          
          
        " style="max-width:85%"><span><a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-core-v2-is-here#" data-featherlight="/img/blog/2026-06-01-dbt-core-v2-is-here/dbt-repo-structure.gif"><img data-toggle="lightbox" alt="Animated comparison of three GitHub repositories: dbt-core (Apache 2.0, Python); dbt-fusion (ELv2, Rust); and dbt-fusion-private (Proprietary, Rust). Large sections of code move from the private repo into the dbt-fusion repo, where they are relicensed to Apache 2.0, and moved into the dbt-core repo. The dbt-fusion repo fades away, indicating it has been archived." title="A high level visualization of the GitHub repositories as they were, and as they are now." src="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/img/blog/2026-06-01-dbt-core-v2-is-here/dbt-repo-structure.gif?v=2"></a></span><span class="title_aGrV">A high level visualization of the GitHub repositories as they were, and as they are now.</span></div>
<p><strong>What's new:</strong></p>
<ul>
<li><strong>We've open-sourced all the code required for a Rust implementation of v2.0 of the dbt framework.</strong> Some of the code was already in the dbt-fusion repository under the ELv2 license. Other parts hadn't made it across yet because we were still rapidly iterating. It's all now in the dbt-core repository, and it's all Apache 2.0 licensed.</li>
<li><strong>That code is the new dbt Core v2.0.</strong> Having the high-performance Rust implementation of dbt as the baseline for all users reduces complexity and makes it easier to keep moving the dbt framework forward. It's in alpha today, and we want your help to make sure it works for everyone as it moves towards GA. Give it a try!</li>
<li><strong>The enhanced, precompiled Fusion binary can now be provided as a managed service by others.</strong> We have relicensed the Fusion binary to be more permissive than ELv2. As before, some features will only work if you've authenticated, either with a free login or a paid dbt platform account. Companies offering Fusion as a managed service must allow end users to enable these premium features.</li>
</ul>
<p><strong>What's not changing:</strong></p>
<ul>
<li><strong>The existing Python code is still available.</strong> We just released a new beta version of dbt Core v1.12.0, and all the old versions are still available on PyPI and GitHub. You don't have to move to v2.x today, tomorrow, or ever. But just like the move from v0 to v1.x back in 2021, over time there will be capabilities that you'll need to upgrade to access.</li>
<li><strong>You can still use the enhanced, precompiled Fusion binary completely for free</strong>. We think this is the best way to use dbt. It contains more capabilities – including a built-in high-performance SQL linter – than you would get from building the Apache codebase yourself, even if you never create a dbt account.</li>
<li><strong>Building dbt remains a team sport</strong>. You can continue to submit issues and PRs to the dbt-core repository, as some 300 community members did on the (now archived) dbt-fusion repository during its preview/beta periods, and as ~1200 others have done on the dbt-core repository during its version 1.x era.</li>
</ul>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="whats-next">What's next?<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-core-v2-is-here#whats-next" class="hash-link" aria-label="Direct link to What's next?" title="Direct link to What's next?">​</a></h2>
<p>Whichever distribution of v2.0 you're upgrading to, it's a major version change and those come with some bumps where we break from the past to get ready for the future. Based on dbt's adoption curve over the last five years, most people reading this weren't part of the migration from dbt v0 to v1.0, so this could be your first time.</p>
<p>It's easier this time: the <a href="https://github.com/dbt-labs/dbt-autofix" target="_blank" rel="noopener noreferrer">dbt-autofix</a> package and our <a href="https://github.com/dbt-labs/dbt-agent-skills/tree/main/skills/dbt-migration/skills/migrating-dbt-core-to-fusion" target="_blank" rel="noopener noreferrer">agent skill</a> for version upgrades mean you can get a long way very quickly. The best way to prepare to migrate is to first <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/docs/dbt-versions/core-upgrade/upgrading-to-v1.12">upgrade to dbt v1.12</a> (or the <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/docs/dbt-versions/dbt-release-tracks">"Latest" release track</a> in the dbt platform).</p>
<p>It enforces many of the behavior changes that are fully removed in v2.0 of the framework, and even ships with the Fusion-powered project parser so that you can check whether your project will parse correctly. Run <code>dbt parse --use-v2-parser</code> to try it out. If your project succeeds, you're good to go, and should check out the <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/docs/local/install-dbt?version=2.0">installation guide</a> to switch over.</p>
<p>If you have further questions, leaders from the newly-combined Fivetran + dbt Labs executive team will be holding a fireside chat on June 25th, 2026. <a href="https://www.getdbt.com/resources/webinars/fivetran-dbt-labs-the-merger-what-s-shipping-in-dbt-and-live-q-and-a" target="_blank" rel="noopener noreferrer">Register for the session here</a>, hosted by <a href="https://www.linkedin.com/in/tristanhandy/" target="_blank" rel="noopener noreferrer">Tristan Handy</a> (Co-founder and President) and <a href="https://www.linkedin.com/in/taylorwcbrown/" target="_blank" rel="noopener noreferrer">Taylor Brown</a> (Co-founder and COO).</p>]]></content>
        <author>
            <name>Joel Labes</name>
        </author>
        <author>
            <name>Grace Goheen</name>
        </author>
        <category label="dbt platform" term="dbt platform"/>
        <category label="data ecosystem" term="data ecosystem"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[The devil is in the docs]]></title>
        <id>https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/the-devil-in-the-docs</id>
        <link href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/the-devil-in-the-docs"/>
        <updated>2026-05-15T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[The devil in the details and the details are the docs that we write. How we're bringing those decisions closer to users in the AI era.]]></summary>
        <content type="html"><![CDATA[<blockquote>
<p><em>"By all means, move at a glacial pace."</em>
— Miranda Priestly, <em><a href="https://en.wikipedia.org/wiki/The_Devil_Wears_Prada_(film)" target="_blank" rel="noopener noreferrer">The Devil Wears Prada</a></em></p>
</blockquote>
<p>There's another scene in <em>The Devil Wears Prada</em> that I think about more than that one. If you haven't seen it yet, I'll try not to spoil it for you. Miranda turns to Andy (Miranda's assistant) and explains, with such impatience, that the <a href="https://en.wikipedia.org/wiki/Cerulean" target="_blank" rel="noopener noreferrer">cerulean blue</a> in Andy's "lumpy sweater" didn't come out of thin air — it's traced back through a chain of deliberate fashion decisions made years earlier, by people who thought carefully about every choice. The sweater Andy bought from the store was the end of a long chain of deliberate <em>curation</em>, carefully veiled to protect the illusion that the sweater effortlessly came into existence.</p>
<p>That's how I'd describe documentation, especially in the AI era. A user — could be a developer, analyst, data engineer, tech writer 😜 — asks an AI tool a question and gets an answer. They don't <em>need</em> to see every decision in the chain behind it: what to include, how to structure it, where the gaps are, what needs updating. But those decisions shape every answer they get. Somewhere upstream, a docs team is making careful, deliberate choices that ripple all the way down to the moment the answer lands in the user's editor.</p>
<p>This blog discusses how docs teams are trying to bring those decisions closer to users — and why that architecture matters more than ever in the AI era.</p>
<div class="theme-admonition theme-admonition-tip admonition_xJq3 alert alert--success"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>Ready to try it?</div><div class="admonitionContent_BuS1"><p>Get started with the <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/docs/dbt-ai/mcp-quickstart-oauth">dbt MCP quickstart guide</a> or check out the <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/docs/dbt-ai/mcp-available-tools#product-docs">product docs tools reference</a> if you're already connected.</p></div></div>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="the-gap-docs-were-there-but-not-natively-delivered">The gap: docs were there, but not natively delivered<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/the-devil-in-the-docs#the-gap-docs-were-there-but-not-natively-delivered" class="hash-link" aria-label="Direct link to The gap: docs were there, but not natively delivered" title="Direct link to The gap: docs were there, but not natively delivered">​</a></h2>
<p>Think of Andy in <em>The Devil Wears Prada</em> — constantly fielding requests for information she could theoretically find, but scrambling each time because it isn't at her fingertips. She's not uninformed. She's just not connected to the right source when it counts.</p>
<p>That is a little similar to the relationship between the <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/docs/dbt-ai/about-mcp">dbt MCP server</a> and the docs:</p>
<ul>
<li>The open source documentation at <a href="https://docs.getdbt.com/" target="_blank" rel="noopener noreferrer">docs.getdbt.com</a> is carefully maintained (by the docs team <em>and</em> our amazing dbt community), up-to-date, and formatted for humans and now, AI.<!-- -->
<ul>
<li>There's an <code>llms.txt</code> index, a full-content flat file, and Markdown output on every page.</li>
<li>We have an <code>AGENTS.md</code> file that lists how to access the docs via web requests.</li>
<li>The source was solid and accessible.</li>
</ul>
</li>
<li>The dbt MCP server is a powerful feature that dbt users interact with dbt through AI tools. It also had a connection to the docs via web searching and training data.<!-- -->
<ul>
<li>It has eight toolset categories: CLI, Semantic Layer, Discovery, Admin API, SQL, Codegen, Fusion, Server Metadata.</li>
<li>But none of them connected directly to the live docs <em>by default</em>. It didn't have our docs as its main source.</li>
</ul>
</li>
</ul>
<p>So when an agent was asked <em>"how do I configure incremental models?"</em>, it could absolutely in theory reach the docs with its own browsing tools, but the experience was inconsistent. Sometimes it fetched a page via web search, sometimes it leaned on training data, or pieced an answer together; and when it <em>did</em> fetch, it usually pulled rendered HTML rather than the Markdown source — heavier, noisier, and less token-efficient. There was no direct, native path inside the server that pointed agents at the canonical docs in their cleanest form by default.</p>
<link href="/css/featherlight-styles.css" type="text/css" rel="stylesheet"><div class="
          docImage_EYbW
          
          
          
          
        " style="max-width:45%"><span><a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/the-devil-in-the-docs#" data-featherlight="/img/blog/2026-04-30-the-devil-is-in-the-docs/dwp-meme.png"><img data-toggle="lightbox" alt="Miranda mad at AI for hallucinating about incremental models (but for real an actual response I received from AI when I was adding the docs tools to the MCP server)" title="Miranda mad at AI for hallucinating about incremental models (but for real an actual response I received from AI when I was adding the docs tools to the MCP server)" src="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/img/blog/2026-04-30-the-devil-is-in-the-docs/dwp-meme.png?v=2"></a></span><span class="title_aGrV">Miranda mad at AI for hallucinating about incremental models (but for real an actual response I received from AI when I was adding the docs tools to the MCP server)</span></div>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="the-research-using-the-data-to-make-better-decisions">The research: using the data to make better decisions<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/the-devil-in-the-docs#the-research-using-the-data-to-make-better-decisions" class="hash-link" aria-label="Direct link to The research: using the data to make better decisions" title="Direct link to The research: using the data to make better decisions">​</a></h2>
<p>Remember when Andy finally does her homework at Runway — studying the designers, the history, learning who's who — so she can anticipate Miranda's needs before being asked? That's the energy this stage called for: pulling the data, weighing the options, and making a deliberate call before committing to a solution.</p>
<p>Earlier this year we'd been discussing docs data and how AI tools are now fetching them to answer questions. The term 'canonical docs' was mentioned and I struggled to understand what it meant and how it was different from the docs we were already building. But then <a href="https://developers.googleblog.com/introducing-the-developer-knowledge-api-and-mcp-server/" target="_blank" rel="noopener noreferrer">Google announced their new docs API and MCP server</a> — then it clicked! Docs are now the source of truth (canonical source) and pretty important in the AI era 💃💃💃!</p>
<p>So we chatted about this and toyed with the idea of either:</p>
<ul>
<li>Building a new docs MCP server, which meant starting from scratch and building all the infrastructure from the ground up</li>
<li>Adding docs tools to the existing dbt MCP server, which meant we would need to add the docs toolset category to the existing dbt MCP server (which already has users and is set up)</li>
<li>Leaving it alone since we have the docs in <a href="https://github.com/dbt-labs/dbt-agent-skills" target="_blank" rel="noopener noreferrer">dbt agent skills</a> (shout out to the amazing work from the DX team!), which is the way forward for users who install the dbt agent skills</li>
</ul>
<p>But that still left us with the question of how to get the docs closer to users in a way that is easy to use and maintain.</p>
<p>We ran some SQL queries in our internal analytics project in dbt platform using Fusion in the <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/docs/install-dbt-extension">dbt VS Code extension</a> and also used <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/docs/explore/dbt-insights">Insights</a> for exploratory analysis.</p>
<p>We saw that the dbt MCP server had these benefits:</p>
<ul>
<li>Great adoption already, with a ton of infrastructure in place. Adding the docs tools would be a natural extension of that, bringing docs directly to users where they already work.</li>
<li>Eight toolset categories already but none of them could directly access docs.getdbt.com.</li>
<li>Open source and free, which also meant every user would get docs access automatically.</li>
</ul>
<p>But the problem was when an agent needed to answer <em>"how do I configure incremental models?"</em> — there was no guaranteed path to the main source of truth, the current docs.</p>
<p>As mentioned above, we already had a solid foundation for AI-readable docs:</p>
<ul>
<li><code>docs.getdbt.com/llms.txt</code> — a page index for AI systems</li>
<li><code>docs.getdbt.com/llms-full.txt</code> — full docs content in a single file</li>
<li><code>.md</code> suffix support on any docs page for clean Markdown output</li>
<li><code>AGENTS.md</code> file that lists how to access the docs via web requests</li>
<li>A published <a href="https://skills.sh/dbt-labs/dbt-agent-skills/fetching-dbt-docs" target="_blank" rel="noopener noreferrer"><code>fetching-dbt-docs</code> skill</a> that teaches AI agents how to access our docs via web requests, installed across Claude Code, Copilot, Gemini CLI, and others</li>
</ul>
<p>The skill approach works great and relies on the someone installing it and the agent knowing the skill existed. However, we were curious to see what would help bring docs even closer to users.</p>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="the-solution-delivering-the-book">The solution: delivering The Book<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/the-devil-in-the-docs#the-solution-delivering-the-book" class="hash-link" aria-label="Direct link to The solution: delivering The Book" title="Direct link to The solution: delivering The Book">​</a></h2>
<p>In <em>The Devil Wears Prada</em>, there's a ritual. Every evening, "The Book" — a secret binder containing the mockup of the upcoming Runway issue — is delivered to Miranda's apartment. Photo proofs, article layouts, ad placements, every choice the editors, stylists, and photographers made that day, bound together in one place. She doesn't go to the office to get it. It arrives, in her space, exactly when she needs it. She reviews it, makes her notes, and what she approves is what gets printed and goes out into the world.</p>
<p>The Book is what carrying a chain of careful decisions actually looks like — bound into one place, delivered to where the next decision gets made.</p>
<p>That's the standard we were trying to meet. Developers shouldn't have to leave their workflow to find docs. The docs — and all the careful decisions baked into them — should arrive in the tool they're already using, at the moment they need to evaluate something and move forward.</p>
<p>The dbt MCP server could already handle lineage lookups, test runs, Semantic Layer queries, job debugging. But ask it <em>"what's the syntax for a snapshot strategy?"</em> and it might get it right or it might get it wrong or it might improvise. Fetching from the web. Training data, or best guess. The Book wasn't being "delivered" consistently.</p>
<p>✨ <strong>The solution:</strong> We added two tools to the dbt MCP server under a new <strong>"Product Docs"</strong> category — the ninth toolset✨:</p>
<ul>
<li><strong><a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/docs/dbt-ai/mcp-available-tools?version=2.0#product-docs"><code>search_product_docs</code></a></strong> — searches docs.getdbt.com and returns titles, URLs, and relevance-ranked descriptions for pages matching your query.</li>
<li><strong><a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/docs/dbt-ai/mcp-available-tools?version=2.0#product-docs"><code>get_product_doc_pages</code></a></strong> — fetches the full Markdown content of one or more docs pages by path or URL.</li>
</ul>
<p>The workflow mirrors how a human would use the docs: Search first to find what's relevant, then fetch the full content. The difference is that it happens inside whatever AI tool you're already using, without a context switching headache.</p>
<p>Alongside this, <a href="https://skills.sh/dbt-labs/dbt-agent-skills" target="_blank" rel="noopener noreferrer">dbt agent skills</a> remain the best path for agents not connected via MCP. The two complement each other: the skill proved the demand; the MCP tools are the native solution.</p>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="how-this-changes-your-day-to-day">How this changes your day-to-day<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/the-devil-in-the-docs#how-this-changes-your-day-to-day" class="hash-link" aria-label="Direct link to How this changes your day-to-day" title="Direct link to How this changes your day-to-day">​</a></h2>
<ul>
<li>Before: Write a macro, hit an unfamiliar function, alt-tab to a browser, search docs, read the page, return to your editor, try to remember where you were. Or ask AI and get an answer that may not be grounded in the canonical, current docs.</li>
<li>After: Ask Claude or your AI tool directly, get an answer grounded in the canonical, current documentation, keep coding! Docs 🤝 canonical source.</li>
</ul>
<p>We also added the product docs toolset to dbt's <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/docs/dbt-ai/wizard-ide">Developer agent</a> experience — bringing the docs closer to users in dbt platform and the Studio IDE. 🎉</p>
<link href="/css/featherlight-styles.css" type="text/css" rel="stylesheet"><div class="
          docImage_EYbW
          
          
          
          
        " style="max-width:70%"><span><a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/the-devil-in-the-docs#" data-featherlight="/img/blog/2026-04-30-the-devil-is-in-the-docs/dwp-dev-agent.png"><img data-toggle="lightbox" alt="Developer agent using the product docs tools" title="Developer agent using the product docs tools" src="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/img/blog/2026-04-30-the-devil-is-in-the-docs/dwp-dev-agent.png?v=2"></a></span><span class="title_aGrV">Developer agent using the product docs tools</span></div>
<p>The Book arrived. No context switch required.</p>
<p>So since we've added the docs toolsets in March, over <strong>1000 unique dbt accounts</strong> have reached for the docs through the dbt MCP server — and every one of those calls means that a user didn't have to leave their workflow to find the docs they needed. That's a win for users and a win for the docs team.</p>
<p>And it's growing fast: <strong>338</strong> docs-tool calls in March (the month they launched), <strong>1,113</strong> in April, and over <strong>6,000</strong> so far in May.</p>
<iframe src="/charts/mcp-docs-usage.html" width="100%" height="500" style="border:none;border-radius:8px;overflow:hidden" title="dbt MCP docs-tool calls per month"></iframe>
<p>And those calls are mostly coming from <em>agents</em> — autonomous, multi-step tools fetching the docs on a user's behalf while they work through a task. That's a different shape of usage than a chat assistant answering a one-off question: the docs aren't just being looked up, they're being pulled into the work itself.</p>
<p>For analysts exploring a shared project, it means understanding what a model does without navigating to a separate tab. For teams working across different dbt setups, it means consistent, authoritative answers regardless of where they're working or who's asking. For the docs team, it means the work we put into writing and maintaining docs.getdbt.com is doing more than it was before — reaching users where they actually are.</p>
<link href="/css/featherlight-styles.css" type="text/css" rel="stylesheet"><div class="
          docImage_EYbW
          
          
          
          
        " style="max-width:55%"><span><a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/the-devil-in-the-docs#" data-featherlight="/img/blog/2026-04-30-the-devil-is-in-the-docs/dwp-wear-chanel.png"><img data-toggle="lightbox" alt="Emily happier that docs are in the MCP server" title="Emily happier that docs are in the MCP server" src="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/img/blog/2026-04-30-the-devil-is-in-the-docs/dwp-wear-chanel.png?v=2"></a></span><span class="title_aGrV">Emily happier that docs are in the MCP server</span></div>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="whats-next">What's next<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/the-devil-in-the-docs#whats-next" class="hash-link" aria-label="Direct link to What's next" title="Direct link to What's next">​</a></h2>
<p>This is the first page of many in this new chapter. But we're planning a few things for the next pages as we continue to try to improve the docs experience:</p>
<ul>
<li><strong>Version-aware docs fetching</strong>: Right now these tools return current docs. A developer on dbt Core v1.10 asking about incremental strategies gets 2026 docs. Version-aware routing — returning the right page for the right dbt version — is the next meaningful improvement, and we're <a href="https://github.com/dbt-labs/dbt-mcp/pull/638" target="_blank" rel="noopener noreferrer">working</a> through it now!</li>
<li><strong>Smarter search ranking</strong>: Relevance is good. Relevance tuned to dbt-specific concepts and query patterns would be better.</li>
<li><strong>Coverage gaps as a signal</strong>: Usage data tells us which pages answer well and which leave users hunting. Spotting the missing, thin, or outdated ones and fixing them means cleaner answers the next time someone asks.</li>
<li><strong>A dedicated dbt docs API or MCP server</strong>: Maybe? It's not the right call right now — one coherent product with an active existing server is the right place to start — but in the future, maybe a standalone docs server could reach every MCP client regardless of whether they use the dbt MCP server at all?</li>
</ul>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="give-it-a-try">Give it a try!<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/the-devil-in-the-docs#give-it-a-try" class="hash-link" aria-label="Direct link to Give it a try!" title="Direct link to Give it a try!">​</a></h2>
<ul>
<li>
<p>If you're new to the MCP server, the <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/docs/dbt-ai/mcp-quickstart-oauth?version=2.0">quickstart guide</a> walks through both local and remote configuration.</p>
</li>
<li>
<p>If you're already connected to the dbt MCP server, the product docs tools are available now. Check out the <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/docs/dbt-ai/mcp-available-tools?version=2.0#product-docs">MCP available tools reference</a> for details.</p>
</li>
</ul>
<p>We'd love to hear your feedback! Open an issue at <a href="https://github.com/dbt-labs/docs.getdbt.com/issues" target="_blank" rel="noopener noreferrer">github.com/dbt-labs/docs.getdbt.com</a> to flag any bugs, typos, wrong info, etc. — or find me in the <a href="https://www.getdbt.com/community/join-the-community" target="_blank" rel="noopener noreferrer">dbt community Slack</a>.</p>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="conclusion">Conclusion<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/the-devil-in-the-docs#conclusion" class="hash-link" aria-label="Direct link to Conclusion" title="Direct link to Conclusion">​</a></h2>
<p>Miranda's point about the cerulean sweater wasn't really about fashion. It was about invisible chains — every deliberate decision ripples further than the person making it can see, and the quality of the source shapes everything downstream.</p>
<p>That's where docs are now. The docs team's decisions — what to include, how to structure it, where the gaps are — used to ripple slowly. A developer might hit them through a Google search, or a Stack Overflow link, or maybe never! Now those decisions arrive in the developer's AI tool, bound into something they can act on, the same way The Book arrives at Miranda's apartment. They flip through, make their call, ship their code. They don't need to see <em>every</em> decision in the chain. They just need the chain to reach them.</p>
<p>We're no longer moving at a glacial pace. The current runs <em>fast</em>. And the devil? Well, it's in the docs.</p>
<p><em>Mirna Wong is a technical writer at dbt Labs who loves em-dashes, pop culture references, and writing about dbt and AI. dbt's product docs are open source — contributions and issues are <strong>always</strong> welcome at <a href="https://github.com/dbt-labs/docs.getdbt.com/issues" target="_blank" rel="noopener noreferrer">github.com/dbt-labs/docs.getdbt.com</a>.</em></p>]]></content>
        <author>
            <name>Mirna Wong</name>
        </author>
        <category label="ai" term="ai"/>
        <category label="docs" term="docs"/>
        <category label="mcp" term="mcp"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Building a better data agent benchmark]]></title>
        <id>https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/building-a-better-data-agent-benchmark</id>
        <link href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/building-a-better-data-agent-benchmark"/>
        <updated>2026-04-15T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[An update on ADE-bench, why context is critical to agentic workflows, and how you can improve your own team's agent eval loop.]]></summary>
        <content type="html"><![CDATA[<p>It's the multitrillion-dollar question that's haunting everyone, from senior software developers and junior lawyers to Hollywood writers and, of course, data analysts and engineers: Can the robots do our jobs?</p>
<p>For us data people, in various forms, the signs are mixed. According to <a href="https://www.anthropic.com/research/labor-market-impacts" target="_blank" rel="noopener noreferrer">recent research from Anthropic</a>, data scientists are already using AI to augment or automate <a href="https://huggingface.co/datasets/Anthropic/EconomicIndex/blob/main/labor_market_impacts/job_exposure.csv#L85" target="_blank" rel="noopener noreferrer">46 percent</a> of their work. In two years, LLMs got good at <a href="https://llm-stats.com/benchmarks/swe-bench-verified" target="_blank" rel="noopener noreferrer">writing code</a>; they are now also <em>very</em> good at <a href="https://spider2-sql.github.io/" target="_blank" rel="noopener noreferrer">writing SQL</a>.<sup><a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/building-a-better-data-agent-benchmark#user-content-fn-1-431d2c" id="user-content-fnref-1-431d2c" data-footnote-ref="true" aria-describedby="footnote-label">1</a></sup></p>
<p>But, as every data person knows, writing queries is not our job; not really. For better or for worse (and perhaps better, if the <a href="https://www.nytimes.com/2026/02/18/opinion/ai-software.html" target="_blank" rel="noopener noreferrer">great code-writing disruption</a> is already here), our job is, as Caitlin Moorman put it over six years ago, <a href="https://locallyoptimistic.com/post/glue-work/" target="_blank" rel="noopener noreferrer">glue work</a>. We map this team's data to that team's goal; we connect questions over here to trends over there. We deal with ambiguity; we say "<a href="https://www.linkedin.com/posts/johnalexandercook_secret-analyst-habits-will-rewrite-an-activity-7333104969694294018-tcbY" target="_blank" rel="noopener noreferrer">it depends</a>." We <a href="https://locallyoptimistic.com/post/run-your-data-team-like-a-product-team/#:~:text=Service%2Doriented%20data%20teams%20aren%E2%80%99t%20effective" target="_blank" rel="noopener noreferrer">tell people no</a>.</p>
<p>And can AI do <em>that</em>? Sure, Claude Code can count the number of accounts in a <code>dim_accounts</code> table, but can it figure out how to differentiate across the <a href="https://developer.salesforce.com/docs/atlas.en-us.object_reference.meta/object_reference/sforce_api_objects_list.htm" target="_blank" rel="noopener noreferrer">24 different account objects</a> in the standard Salesforce schema? Can it figure out what "account" means, when the marketing team has one definition, the sales team has another, and the engineering team uses a third? Can it solve the <a href="https://www.getdbt.com/blog/modeling-marketing-attribution" target="_blank" rel="noopener noreferrer">lost cause of marketing attribution</a>? Can it <a href="https://openai.com/index/sycophancy-in-gpt-4o/" target="_blank" rel="noopener noreferrer">say no</a>?</p>
<p>Last year, with support from dbt Labs and <a href="https://getmacro.com/" target="_blank" rel="noopener noreferrer">Macro</a>, an automatic context optimizer for analytical agents, we set out to build a benchmark to help us answer these questions. Though the data and engineering communities had already created a number of analytical and data science benchmarks (several of which we borrowed from, and are extremely grateful for), most of them focused on testing how well agents perform specific technical tasks, like writing SQL queries or developing predictive models. Our goal was to create a new open-source benchmark that tests how AI agents work <em>in realistic data environments</em>: in big databases, across <a href="https://docs.getdbt.com/best-practices/how-we-structure/1-guide-overview?version=2.0#guide-structure-overview" target="_blank" rel="noopener noreferrer">layered dbt projects</a>, answering complex analytics and data engineering challenges.</p>
<p>That project became <a href="https://github.com/dbt-labs/ade-bench" target="_blank" rel="noopener noreferrer"><strong>ADE-bench</strong></a>.</p>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="how-ade-bench-works">How ADE-bench works<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/building-a-better-data-agent-benchmark#how-ade-bench-works" class="hash-link" aria-label="Direct link to How ADE-bench works" title="Direct link to How ADE-bench works">​</a></h2>
<p>ADE-bench, which was heavily inspired by <a href="https://www.tbench.ai/" target="_blank" rel="noopener noreferrer">terminal-bench</a> and <a href="https://spider2-sql.github.io/" target="_blank" rel="noopener noreferrer">Spider 2.0</a>, has two main components:</p>
<ul>
<li>Data environments</li>
<li>Tasks</li>
</ul>
<h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="data-environments">Data environments<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/building-a-better-data-agent-benchmark#data-environments" class="hash-link" aria-label="Direct link to Data environments" title="Direct link to Data environments">​</a></h3>
<p>Data environments are combinations of dbt projects and databases. dbt projects can be arbitrarily simple or complex, though most of ADE-bench's projects contain a comprehensive set of data models for their associated database: there are staging layers, intermediate layers, and marts; projects contain macros; there are third-party sources and associated <a href="https://docs.getdbt.com/docs/build/packages?version=2.0" target="_blank" rel="noopener noreferrer">dbt packages</a>. This complexity is very much by design, and exactly the sort of environments we wanted to test agents in.</p>
<p>These projects are then run on top of DuckDB and Snowflake databases.<sup><a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/building-a-better-data-agent-benchmark#user-content-fn-2-431d2c" id="user-content-fnref-2-431d2c" data-footnote-ref="true" aria-describedby="footnote-label">2</a></sup> DuckDB was used for convenience: DuckDB databases can be shared as standalone files, and DuckDB databases can be run locally without any complex hosting requirements or third-party services. Because many companies run their production data tools on large cloud-hosted databases like Snowflake, ADE-bench also includes scripts that automatically create sandbox schemas in Snowflake, upload DuckDB databases into those schemas, and migrate the dbt projects to support Snowflake's dialect of SQL rather than DuckDB's.</p>
<h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="tasks">Tasks<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/building-a-better-data-agent-benchmark#tasks" class="hash-link" aria-label="Direct link to Tasks" title="Direct link to Tasks">​</a></h3>
<p>Tasks are test questions. A task might ask an agent to fix a bug, to update a model, to refactor an entire project, or to solve some analytical problem. Each task also includes an answer key that ADE-bench uses to check the agent's work. Tasks can include as many evaluation criteria as necessary, including checking for the existence of models and comparing tables' content to answer keys.</p>
<p>When ADE-bench is asked to solve a task, the test harness prepares the data environment for the agent, gives the agent its instructions, and then checks its work. These are the stylized steps that ADE-bench follows to execute a task:</p>
<ol>
<li><strong>Create a sandbox data environment.</strong> ADE-bench launches a dedicated Docker container for the task. It loads the corresponding project into the container, and, if the task is run against Snowflake, creates a sandbox database inside of Snowflake.</li>
<li><strong>Run task-specific setup script.</strong> Because a lot of data teams' actual work involves fixing something that is broken (data arrives in the database in a malformed state; dbt models get out of sync with one another; we all know these horrors), tasks can also include pre-test scripts that modify just that task's data environment. Most commonly, these scripts introduced errors that we wanted the agent to fix, or deleted models we wanted to ask the agent to create.</li>
<li><strong>Give the sandbox to the agent.</strong> An AI agent is given the project, the database, and its task. ADE-bench then waits for the agent to say it's done.</li>
<li><strong>Snapshot the agent's changes.</strong> Once the agent stops working, ADE-bench takes a snapshot of all of the changes the agent made. These get presented in a diff in the final results.</li>
<li><strong>Score the result.</strong> The changes are evaluated. ADE-bench includes a number of default test types, like comparing a table to a solution key, or checking for the existence of a dbt model.</li>
<li><strong>Clean everything up.</strong> ADE-bench records the results of all the tests, logs the agent's work, and then deletes the container.</li>
</ol>
<p>For much more detail on how ADE-bench runs and how it can be configured, you can find additional documentation on <a href="https://github.com/dbt-labs/ade-bench" target="_blank" rel="noopener noreferrer">GitHub</a>.</p>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="how-and-why-ade-benchs-goal-changed">How (and why) ADE-bench's goal changed<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/building-a-better-data-agent-benchmark#how-and-why-ade-benchs-goal-changed" class="hash-link" aria-label="Direct link to How (and why) ADE-bench's goal changed" title="Direct link to How (and why) ADE-bench's goal changed">​</a></h2>
<p>When we first began developing ADE-bench, our original goal was to compare how different models performed at different analytical tasks. We wanted a leaderboard: Which LLM should you use? How much closer are the labs getting to building a model that can do real analytical work?</p>
<p>But in the time since we built it, it's become clear that the biggest gains were unlikely to come from better models, <a href="https://a16z.com/your-data-agents-need-context/" target="_blank" rel="noopener noreferrer">but from more <em>context</em></a>:</p>
<blockquote>
<p>Over the past year, the market has realized that data and analytics agents are essentially useless without the right context; they aren't able to tease apart vague questions, decipher business definitions, and reason across disparate data effectively.</p>
</blockquote>
<p><a href="https://openai.com/index/inside-our-in-house-data-agent/" target="_blank" rel="noopener noreferrer">OpenAI's in-house data agent</a> is built on top of an internal knowledge base and "company context," like Slack, Google Docs, and Notion. When describing their internal agentic data analyst, Ramp said <a href="https://engineering.ramp.com/post/meet-ramp-research" target="_blank" rel="noopener noreferrer">it wouldn't work without business context</a>:</p>
<blockquote>
<p>Even with the relevant data context, the agent struggled to connect its understanding of our data to the different domains of Ramp's business. Much of that knowledge is tacit and lives with domain owners on the analytics team. To give our agent an expert-level understanding of each domain, we relied on domain owners to write up technical documentation on their respective areas. These documents were then organized into a file system that Ramp Research can access as needed.</p>
</blockquote>
<p>And critically, to improve their agent, <strong>they test giving it better context:</strong></p>
<blockquote>
<p>This suite enabled us to close the feedback loop: update context, run tests, and confirm improvements.</p>
</blockquote>
<p>This presents a fundamental challenge for building analytical benchmarks. If the most effective way to improve an analytics agent is to give it more business context, <strong>a synthetic test that exists in a sandbox will always be incomplete.</strong> You can imagine the conversation: "Your AI analyst came in eighth on this benchmark, and that doesn't seem very good," says the data team manager. "Well yeah," says the vendor, "because that benchmark doesn't use our proprietary Enterprise Decision Context Hub™ when it answers questions." And the vendor would have a good point. If a benchmark is intended to compare different products to one another, that benchmark can't exclude the most important way that those products can differentiate themselves.</p>
<p>Moreover, for most in-house data teams, managing context (writing better documentation; adding Slack conversations or meeting recordings to an internal knowledge base; creating a repository of example queries) is the most meaningful way that they can get more out of today's AI products. When we first <a href="https://www.youtube.com/watch?v=cX2yvpqRTsA" target="_blank" rel="noopener noreferrer">shared ADE-bench at Coalesce 2025</a> (now <a href="https://www.getdbt.com/dbt-summit" target="_blank" rel="noopener noreferrer">dbt Summit</a>), that was what people immediately wanted to know: not which model they should use, but which architectural configurations are best.</p>
<p>So how do you build a benchmark to answer <em>that</em>?</p>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="three-ways-to-build-a-better-benchmark">Three ways to build a better benchmark<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/building-a-better-data-agent-benchmark#three-ways-to-build-a-better-benchmark" class="hash-link" aria-label="Direct link to Three ways to build a better benchmark" title="Direct link to Three ways to build a better benchmark">​</a></h2>
<h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="create-an-entire-case-study">Create an entire case study<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/building-a-better-data-agent-benchmark#create-an-entire-case-study" class="hash-link" aria-label="Direct link to Create an entire case study" title="Direct link to Create an entire case study">​</a></h3>
<p>Most benchmarks, ours included, try to test different domains. There are datasets about SaaS businesses, and e-commerce, and sometimes, sports and science and other, non-business topics. Though this range is useful, a better benchmark might be one that focuses on a single business, and tries to simulate as much context around it as possible. This is probably infeasible (how do you fake recordings of calls?), but in a world of agents <a href="https://moltbook.com/" target="_blank" rel="noopener noreferrer">talking</a> to one another, <a href="https://www.nytimes.com/2026/02/08/briefing/the-church-of-molt.html" target="_blank" rel="noopener noreferrer">weirder things have happened</a>.</p>
<h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="find-a-few-benchmark-sponsors">Find a few benchmark "sponsors"<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/building-a-better-data-agent-benchmark#find-a-few-benchmark-sponsors" class="hash-link" aria-label="Direct link to Find a few benchmark &quot;sponsors&quot;" title="Direct link to Find a few benchmark &quot;sponsors&quot;">​</a></h3>
<p>More realistically, an existing company could "sponsor" a benchmark by making their data <em>and their context</em> available to test against. This wouldn't necessarily require a company to make their data public; it would instead require a few companies to act as stewards of an internal benchmark that they regularly run new agents against. (There is already a <a href="https://cursor.com/blog/cursorbench" target="_blank" rel="noopener noreferrer">precedent for this</a> with coding benchmarks.)</p>
<p>There are two complications with this, however. First, internal benchmarks are inherently harder to trust, especially if they're managed by companies that are also selling their own agents. Second, unlike coding agents, which are often terminal apps run against a codebase, many analytical agents are SaaS products that connect to other SaaS services, and need to be set up before they are fully functional (e.g., they run inside a database like Snowflake or Databricks, they manage their own documentation, etc.). This makes it impractical, though again not impossible, for one company to test lots of agents at once.</p>
<h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="make-it-easier-for-companies-to-conduct-and-share-their-own-tests">Make it easier for companies to conduct and share their own tests<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/building-a-better-data-agent-benchmark#make-it-easier-for-companies-to-conduct-and-share-their-own-tests" class="hash-link" aria-label="Direct link to Make it easier for companies to conduct and share their own tests" title="Direct link to Make it easier for companies to conduct and share their own tests">​</a></h3>
<p>Right now, hundreds of data teams are trying to figure out what works and what doesn't. There are surely lots of variants in those efforts (different agents, different setups, different prompts, different problem domains), but most data teams have much more important day jobs to do. To that end, we hope that ADE-bench can be a useful start. Teams can replace our tasks with their own, and use clones of their own database and dbt repo to design their own tests.</p>
<p>If you want to do this, the <a href="https://getdbt.slack.com/archives/C0A2FTCKTME" target="_blank" rel="noopener noreferrer">#tools-ade-bench</a> channel in the <a href="https://getdbt.com/community" target="_blank" rel="noopener noreferrer">dbt Community Slack</a> is a good place to get started.</p>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="how-to-make-your-own-tasks">How to make your own tasks<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/building-a-better-data-agent-benchmark#how-to-make-your-own-tasks" class="hash-link" aria-label="Direct link to How to make your own tasks" title="Direct link to How to make your own tasks">​</a></h2>
<p>Here are some of the most important lessons we learned when designing tests:</p>
<h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="the-prompt-matters-as-much-as-the-problem">The prompt matters as much as the problem<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/building-a-better-data-agent-benchmark#the-prompt-matters-as-much-as-the-problem" class="hash-link" aria-label="Direct link to The prompt matters as much as the problem" title="Direct link to The prompt matters as much as the problem">​</a></h3>
<p>At first, we wanted to test different types of analytical problems: Can agents debug syntax errors? Can they work with dbt macros? Can they create new models? The former would be the easy tests; the latter would be the harder ones.</p>
<p>However, the <em>type</em> of problem often mattered less than how the problem was described.</p>
<p>In some cases, we introduced breaking changes to models and told the agent what wasn't working and the error that the database was returning. In other cases, we just said, "Something is broken." Unsurprisingly, these prompts returned different results.</p>
<p>That may be obvious, but it has an important implication: You're often testing your prompts as much as the agent. Agents can solve very hard problems with a lot of direction; we sometimes found that they struggled at simple problems when directions were vague.<sup><a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/building-a-better-data-agent-benchmark#user-content-fn-3-431d2c" id="user-content-fnref-3-431d2c" data-footnote-ref="true" aria-describedby="footnote-label">3</a></sup> So, when designing tests, we recommend varying the prompts<sup><a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/building-a-better-data-agent-benchmark#user-content-fn-4-431d2c" id="user-content-fnref-4-431d2c" data-footnote-ref="true" aria-describedby="footnote-label">4</a></sup>, because once an agent is in the wild, you never know how people might interact with it.</p>
<h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="ask-about-the-data-itself">Ask about the data itself<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/building-a-better-data-agent-benchmark#ask-about-the-data-itself" class="hash-link" aria-label="Direct link to Ask about the data itself" title="Direct link to Ask about the data itself">​</a></h3>
<p>The questions that seemed to trip up agents the most were the ones that couldn't be answered using the codebase alone. A bad value in a table breaks a join; a few rows have numeric values that are impossibly high; a WHERE clause uses the wrong string for a filter; one table says a customer is in one state, and a different table says they're in another. These problems can't be solved unless you inspect the data itself.</p>
<p>Because most major LLMs are now so heavily trained on coding tasks, analytical agents are often pretty good at finding problems that exist entirely in the code, like syntax errors or bugs in the logic. They seem to have a harder time with problems that require the agent to query the data first.</p>
<p>When designing tasks, this is a good class to test: Introduce a few bad needles into a haystack of data, tell the agent about something that broke because of it, and see if it can track down what went wrong.</p>
<h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="check-their-work">Check their work<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/building-a-better-data-agent-benchmark#check-their-work" class="hash-link" aria-label="Direct link to Check their work" title="Direct link to Check their work">​</a></h3>
<p>Sometimes, AI agents solved problems I didn't think they would solve. Sometimes, they stumbled through very basic problems, often by pulling on the wrong initial thread, and then spiraling in the wrong direction.</p>
<p>None of this shows up in the final pass/fail result of a test. But it shows up in the diffs, and in the chain of thought logs, both of which ADE-bench captures.</p>
<p>When designing tests, these logs were just as useful as the results themselves. They give you a sense of how the agent "thinks," and what assumptions it's making about different types of problems. And if nothing else, reading these logs was a fascinating and sometimes eerie peek into the "brain" of an LLM, and how they reason their way through data problems. In several cases, especially when working on tasks that required the agent to answer analytical questions, the models sometimes considered angles that we did not.</p>
<h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="remember-that-the-test-is-not-the-territory">Remember that the test is not the territory<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/building-a-better-data-agent-benchmark#remember-that-the-test-is-not-the-territory" class="hash-link" aria-label="Direct link to Remember that the test is not the territory" title="Direct link to Remember that the test is not the territory">​</a></h3>
<p>Speaking of analytical questions, one major challenge with testing how well an agent solves analytical problems is that many analytical questions don't have exact answers. "Which marketing campaign performed the best?" is a question that is, one, common, two, important for a good agent to answer, and three, <em>very vague</em>. But a good benchmark can't ignore questions like these simply because they're hard to score; these are, after all, exactly the sorts of questions people want answered.</p>
<p>Fortunately, benchmarks don't need to reinvent the wheel with questions like this. <em>People</em> have been tested on questions like these for decades, and there is a popular solution: The multiple-choice question. Offer the agent a number of different possible answers, and tell it to choose which one (or ones) are viable answers.</p>
<p>For example, here is a question in ADE-bench:</p>
<blockquote>
<p>I asked an analyst to figure out if drivers have gotten faster or slower over time. To help me figure this out, they created a new model called <code>analysis__lap_times</code> that has three columns:</p>
<ul>
<li><code>circuit_name</code>: The name of the track.</li>
<li><code>race_year</code>: The year of the race.</li>
<li><code>avg_adjusted_lap_time_in_ms</code>: The average lap time in milliseconds, adjusted for pit stop times.</li>
</ul>
<p>Which of the following are problems with this analysis? Choose all that apply.</p>
<ul>
<li>A. It does not account for changes to the track.</li>
<li>B. It does not handle incomplete or unfinished laps correctly.</li>
<li>C. It double-counts lap times with multiple pit stops.</li>
<li>D. Lap times could be affected by caution flags.</li>
<li>E. The adjustment for pit stops is incorrect.</li>
<li>F. It measures lap times by race rather than by race track.</li>
</ul>
<p>Create a dbt model called <code>analysis__answer</code> that has one row and one column called <code>answer</code>. Include the letters of the correct answers. For example, if the correct answers are A and B, the answer should be "AB".</p>
</blockquote>
<p>Of course, in production, agents won't be given these choices. But remember: Tests don't need to replicate the real world to be informative, just as the LSAT doesn't need to replicate life as a lawyer to provide valuable information to a law school. The point is to find strong correlations. If stronger analytical agents do better on multiple-choice questions than weaker agents (and, from reading how agents reasoned through these problems, we believe they do), then the questions are valuable.</p>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="please-share-what-youre-learning">Please share what you're learning<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/building-a-better-data-agent-benchmark#please-share-what-youre-learning" class="hash-link" aria-label="Direct link to Please share what you're learning" title="Direct link to Please share what you're learning">​</a></h2>
<p>Whether we like it or not, <a href="https://roundup.getdbt.com/p/how-to-actually-move-up-the-stack" target="_blank" rel="noopener noreferrer">AI is changing how we all work with data</a>, and none of us can be sure what our jobs will look like in the months and years ahead. But we believe that benchmarks are an important part of that story, not only because they can help us understand what AI is capable of, but because they can help figure out which environments, configurations, and context libraries make AI more effective, and which don't.</p>
<p>We're excited to keep working on that project, to keep experimenting with new ways to experiment. And we'd love for you to join us along the way.</p>
<!-- -->
<section data-footnotes="true" class="footnotes"><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5 sr-only" id="footnote-label">Footnotes<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/building-a-better-data-agent-benchmark#footnote-label" class="hash-link" aria-label="Direct link to Footnotes" title="Direct link to Footnotes">​</a></h2>
<ol>
<li id="user-content-fn-1-431d2c">
<p>On one hand, you could argue that a query accuracy rate of 97 percent is too low when you're reporting on critical financial numbers or driving important strategic decisions. On the other hand, as someone who only gets <a href="https://www.youtube.com/watch?v=J__6wjBW9Fg&amp;t=266s" target="_blank" rel="noopener noreferrer">76 percent</a> of their queries right, I'm impressed by 97 percent. <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/building-a-better-data-agent-benchmark#user-content-fnref-1-431d2c" data-footnote-backref="" aria-label="Back to reference 1" class="data-footnote-backref">↩</a></p>
</li>
<li id="user-content-fn-2-431d2c">
<p>We considered supporting more databases, but we found that it probably wasn't worth the effort. Frontier LLMs are now good enough at writing SQL that they rarely get tripped up on any of the major SQL dialects. Moreover, our intention wasn't to test how well agents write different flavors of SQL; it was to test how well agents navigate complex environments with large and confusing data models. Against that problem, performance was unlikely to vary enough by database to justify supporting many more database types. <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/building-a-better-data-agent-benchmark#user-content-fnref-2-431d2c" data-footnote-backref="" aria-label="Back to reference 2" class="data-footnote-backref">↩</a></p>
</li>
<li id="user-content-fn-3-431d2c">
<p>When prompts were vague, agents tended to be overeager. They often found the issue that we were hoping they would find, but they would then sometimes make other changes as well. This very much seems to be in their nature. <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/building-a-better-data-agent-benchmark#user-content-fnref-3-431d2c" data-footnote-backref="" aria-label="Back to reference 3" class="data-footnote-backref">↩</a></p>
</li>
<li id="user-content-fn-4-431d2c">
<p>For this reason, ADE-bench allows you to create multiple prompt variants for the same task. <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/building-a-better-data-agent-benchmark#user-content-fnref-4-431d2c" data-footnote-backref="" aria-label="Back to reference 4" class="data-footnote-backref">↩</a></p>
</li>
</ol>
</section>]]></content>
        <author>
            <name>Benn Stancil</name>
        </author>
        <category label="ai" term="ai"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Semantic Layer vs. Text-to-SQL: 2026 Benchmark Update]]></title>
        <id>https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/semantic-layer-vs-text-to-sql-2026</id>
        <link href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/semantic-layer-vs-text-to-sql-2026"/>
        <updated>2026-04-07T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[With 2026's best models, the dbt Semantic Layer hits near-100% accuracy for covered queries. Here's what changed and what didn't in our updated benchmark.]]></summary>
        <content type="html"><![CDATA[<p>There are two primary ways to get answers from your data using LLMs today: have the model write SQL directly, or have it query through a structured ontology like the dbt Semantic Layer. Both work. Companies are getting real value from each. But they fail in very different ways, and understanding those failure modes is what actually matters when you're deciding which to use.</p>
<p>In 2023, <a href="https://roundup.getdbt.com/p/semantic-layer-as-the-data-interface" target="_blank" rel="noopener noreferrer">we ran a benchmark</a> comparing the two approaches and the Semantic Layer won handily. But 2023 is roughly 10 million years ago in LLM time. Models have gotten dramatically better at writing SQL. So we reran the benchmark with the latest generation models to see whether the gap has closed.</p>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="tldr">TL;DR<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/semantic-layer-vs-text-to-sql-2026#tldr" class="hash-link" aria-label="Direct link to TL;DR" title="Direct link to TL;DR">​</a></h2>
<div class="filterableTableContainer_mhtg"><div class="filterableTableContainer_mhtg"></div><table style="display:none"></table><table style="display:none"><thead><tr><th>Model</th><th>Method</th><th>Accuracy %</th></tr></thead><tbody><tr><td>claude-sonnet-4-6</td><td>Text-to-SQL</td><td>90.0%</td></tr><tr><td>claude-sonnet-4-6</td><td>Semantic Layer</td><td>98.2%</td></tr><tr><td>gpt-5.3-codex</td><td>Text-to-SQL</td><td>84.1%</td></tr><tr><td>gpt-5.3-codex</td><td>Semantic Layer</td><td>100.0%</td></tr></tbody></table><div class="tableWrapper_oiMt"><div class="searchBar_xnmH"><div class="searchContainer_fLyJ"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M416 208c0 45.9-14.9 88.3-40 122.7L502.6 457.4c12.5 12.5 12.5 32.8 0 45.3s-32.8 12.5-45.3 0L330.7 376c-34.4 25.2-76.8 40-122.7 40C93.1 416 0 322.9 0 208S93.1 0 208 0S416 93.1 416 208zM208 352a144 144 0 1 0 0-288 144 144 0 1 0 0 288z"></path></svg><input type="text" placeholder="Search table..." class="searchInput_xT8h" aria-label="Search table" value=""></div></div><table class="filterableTable_QAKT"><thead><tr></tr></thead><tbody><tr><td colspan="5" style="text-align:center;padding:20px">Loading table...</td></tr></tbody></table></div></div><div class="tableWrapper_oiMt"><div class="searchBar_xnmH"><div class="searchContainer_fLyJ"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M416 208c0 45.9-14.9 88.3-40 122.7L502.6 457.4c12.5 12.5 12.5 32.8 0 45.3s-32.8 12.5-45.3 0L330.7 376c-34.4 25.2-76.8 40-122.7 40C93.1 416 0 322.9 0 208S93.1 0 208 0S416 93.1 416 208zM208 352a144 144 0 1 0 0-288 144 144 0 1 0 0 288z"></path></svg><input type="text" placeholder="Search table..." class="searchInput_xT8h" aria-label="Search table" value=""></div></div><table class="filterableTable_QAKT"><thead><tr></tr></thead><tbody><tr><td colspan="5" style="text-align:center;padding:20px">Loading table...</td></tr></tbody></table></div>]]></content>
        <author>
            <name>Jason Ganz</name>
        </author>
        <author>
            <name>Benoit Perigaud</name>
        </author>
        <category label="ai" term="ai"/>
        <category label="semantic-layer" term="semantic-layer"/>
        <category label="llm" term="llm"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[The Catalog Linked Database Diaries: On Freshness and Writes]]></title>
        <id>https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/catalog-linked-databases</id>
        <link href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/catalog-linked-databases"/>
        <updated>2026-03-26T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Learn about catalog linked databases with Apache Iceberg.]]></summary>
        <content type="html"><![CDATA[<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="the-catalog-linked-database-diaries-on-freshness-and-writes">The Catalog Linked Database Diaries: On Freshness and Writes<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/catalog-linked-databases#the-catalog-linked-database-diaries-on-freshness-and-writes" class="hash-link" aria-label="Direct link to The Catalog Linked Database Diaries: On Freshness and Writes" title="Direct link to The Catalog Linked Database Diaries: On Freshness and Writes">​</a></h2>
<p>Last November, at dbt Summit, Jeremy introduced dbt’s multi-platform Iceberg capabilities.</p>
<div style="display:flex;justify-content:center"><iframe width="560" height="315" src="https://www.youtube.com/embed/bRJJkeJkUsE?si=mQTD3jUNpPqvwrJb" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin"></iframe></div>
<p>What intrigued us most was the promised interconnectivity of Databricks Unity Catalog and Snowflake catalog-linked databases.</p>
<p>AI’s all the rage, but another little revolution is taking shape: Teams are breaking their data storage out of vendor-specific platforms. For months, we have been chatting with users excited to adopt Iceberg as a core pillar of their data architecture. The Iceberg table format and Iceberg REST catalogs are the emerging standards powering that flexibility.</p>
<p>For dbt’s part, this shows up in two concrete use cases:</p>
<ul>
<li><strong>dbt projects at scale</strong>: Teams share one logical database, with many schemas and hundreds to thousands of tables</li>
<li><strong>Cross-platform mesh</strong>: One project in Snowflake, one in Databricks, sharing data without juggling manual refreshes or metadata pointers</li>
</ul>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="what-is-a-catalog-linked-database">What is a Catalog Linked Database?<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/catalog-linked-databases#what-is-a-catalog-linked-database" class="hash-link" aria-label="Direct link to What is a Catalog Linked Database?" title="Direct link to What is a Catalog Linked Database?">​</a></h2>
<p>In the Iceberg model, the catalog is the system of record for table metadata—schemas, snapshots, and evolution. It’s designed so multiple engines can interoperate against that same metadata layer. A catalog-linked database (CLD) is Snowflake’s way of exposing an open Apache Iceberg catalog, and all the Iceberg tables it contains, inside Snowflake as just another database.</p>
<p>The dream is for teams to share Iceberg tables across platforms without recreating their metadata pointers one by one or copying actual data. Consider an organization with finance using figures in Databricks and a marketing team using Snowflake. The Snowflake team wants that upstream data fresh and even wants to backport manual row updates now and then. Old-school synced tables would treat Databricks as a source of truth. With Iceberg and a CLD-enabled architecture, both data platforms point to the same catalog-defined source of truth.</p>
<p>Some upfront configuration work in Snowflake buys you seamless cross-platform queries on seamlessly synced data objects—that’s the on-paper guarantee. (Snowflake recently published a <a href="https://docs.snowflake.com/en/user-guide/tutorials/tables-iceberg-set-up-bidirectional-access-to-unity-catalog" target="_blank" rel="noopener noreferrer">step-by-step tutorial</a> for using CLDs to enable bidirectional data sharing with Databricks — unimaginable a few years ago, and achievable today.)</p>
<p>As we developed our testing suite, we wondered what happens at scale for both reads and writes. Turn up the chaos: what happens when both are happening at once? For example, if the accounting team writes into a Databricks cluster at 6 a.m. every morning, but the synchronization step to the marketing team’s Snowflake cluster takes 2-3 hours, when will it be safe for their morning data analysis jobs to kick off?</p>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="our-testing-regimen">Our testing regimen<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/catalog-linked-databases#our-testing-regimen" class="hash-link" aria-label="Direct link to Our testing regimen" title="Direct link to Our testing regimen">​</a></h2>
<p>Based on our telemetry of real-world dbt projects, we see that large projects number in the hundreds of models. Some number in the thousands. For the purposes of our testing, we make the riskiest assumption that <em>every single model</em> would be materialized as an Iceberg table. This is our upper bound. (It’s rare behavior in dbt projects adopting Iceberg, but a team could have legitimate reasons for choosing this.)</p>
<p>At these scales, catalog behavior, metadata operations, and refresh mechanics really start to matter. We observed latencies and frictions in the hundreds, but for science, we pushed this to its extreme. We loaded 500k tables into one database and tested write performance, synchronization promises, etc.</p>
<ol>
<li><strong>Reading at scale:</strong> What’s the overhead when Snowflake reads tables owned elsewhere?</li>
<li><strong>Writing at scale:</strong> How does performance change when you’re creating/updating lots of tables and querying big sums of metadata?</li>
<li><strong>Freshness under change:</strong> When one platform updates data, how reliably and quickly does the other see it?</li>
</ol>
<p>We've published our full testing regimen and detailed findings, for anyone who wants to take a deeper look: <a href="https://github.com/dbt-labs/snow-dbx-iceberg-benchmark" target="_blank" rel="noopener noreferrer">https://github.com/dbt-labs/snow-dbx-iceberg-benchmark</a></p>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="reads-at-scale">Reads at scale: Good performance, but only after platforms sync<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/catalog-linked-databases#reads-at-scale" class="hash-link" aria-label="Direct link to Reads at scale: Good performance, but only after platforms sync" title="Direct link to Reads at scale: Good performance, but only after platforms sync">​</a></h2>
<p>Using TPC-H queries over large benchmarking datasets, we found that once data is visible and up to date, querying those Iceberg tables from Snowflake is as fast as you’d want in any reasonable analytics workflow. Databricks querying the same data from the owning side is speedy too.</p>
<p>The catch is that “read performance” is really only half the story. In practice, what users experience is not “how fast is this query,” but “am I even querying fresh data?” When freshness slips, CLDs stop feeling like a pipe and start feeling like waiting for a package held up in customs.</p>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="writes-and-changes-at-scale">Writes and change at scale: The compute bottleneck<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/catalog-linked-databases#writes-and-changes-at-scale" class="hash-link" aria-label="Direct link to Writes and change at scale: The compute bottleneck" title="Direct link to Writes and change at scale: The compute bottleneck">​</a></h2>
<p>When Snowflake is the one making lots of changes (creating tables, updating metadata, producing many Iceberg commits), the job runs the query against the upstream Databricks objects. A query might take twice as long, but the data is synchronized across both platforms. Write throughput becomes the limiting factor. In a dbt-shaped workload—many small/medium table operations rather than one giant append—this can make runs slow and sometimes fragile under contention. This can lead to outright failures claiming your table no longer exists.</p>
<p>Now, when Databricks is making changes, writes are the same as in any ordinary Databricks workflow. The difficulty becomes Snowflake's ability to reflect those changes.</p>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="the-biggest-finding">The biggest finding: As scale increases, refresh latency does too<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/catalog-linked-databases#the-biggest-finding" class="hash-link" aria-label="Direct link to The biggest finding: As scale increases, refresh latency does too" title="Direct link to The biggest finding: As scale increases, refresh latency does too">​</a></h2>
<p>CLDs promise fast syncing. We found this is relatively true at small and medium scales. However, at larger scales, we observed that changes made by Databricks could take far longer than advertised on the tin to synchronize. Generally, we experienced auto-refresh waits 2x longer than expected. When we dialed things up to 500k tables, the refresh on Snowflake for a trivial Databricks <code>INSERT</code> could take two days to propagate. Some tables seemed to get “stuck.” Now, we eventually learned how to manually force refreshes for individual objects (i.e. hacking refresh-related settings to jog the system). But, we found it difficult to predict when data updates would propagate from Databricks back to Snowflake (the good news is that we hear the fine folks at Snowflake have ergonomic improvements on the way). We mostly operated on a gut feeling of when data would arrive.</p>
<p>Mulling over our experiences, we believe the question of whether and how you should adopt Snowflake CLDs comes down to scale and latency:</p>
<ol>
<li>How many Iceberg tables are you syncing across multiple engines?</li>
<li>Do your workflows require that Snowflake has a near-real-time view of externally managed Iceberg? Or can you treat it as a view that might be stale, accept eventual consistency, and live without clear guarantees unless you build your own manual playbook and monitoring framework?</li>
</ol>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="interoperability-friction">Interoperability friction: Why it’s not just the metadata<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/catalog-linked-databases#interoperability-friction" class="hash-link" aria-label="Direct link to Interoperability friction: Why it’s not just the metadata" title="Direct link to Interoperability friction: Why it’s not just the metadata">​</a></h2>
<p>Two non-performance issues showed up quickly:</p>
<ul>
<li>Naming, quoting, and casing differences become friction points when dbt is generating objects that need to be understood identically by two engines. Our deep dive has given us ideas for dbt to abstract over these ergonomic challenges. In the future, users shouldn’t need to memorize the casing/quoting rules of every catalog/engine combo. For now, unfortunately, that’s just the cost of doing platform-agnostic business.</li>
<li>Metadata and refresh behavior become part of your job. You’re managing tables and the system that decides when tables “exist.” And those <code>show iceberg tables</code> queries are slow.</li>
</ul>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="the-takeaway">The takeaway<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/catalog-linked-databases#the-takeaway" class="hash-link" aria-label="Direct link to The takeaway" title="Direct link to The takeaway">​</a></h2>
<p>CLDs work—up to a point. They solve recurring problems about keeping data connected across platforms. If the number of tables or update volume is very large (on the order of tens of thousands), the pattern stops being a useful abstraction. The same goes if you depend on per-second precision for synchronizing writes. But until you approach that edge, CLDs really do make it possible to treat external Iceberg catalogs like any other database.</p>
<p>For us, that can unlock some very exciting capabilities within customers’ dbt workflows—cross-platform mesh, external sources, and maybe even running the same dbt project / DAG against multiple warehouses. We believe that Iceberg integrations will continue to improve, becoming more performant and easier to use. We need only look to the past year of features (including Snowflake CLDs and Databricks' native managed Iceberg tables, the two features that made this story possible) to be excited for what’s coming in the next one.</p>
<p>And finally, we can’t close without giving a nod to the Unity Catalog team for partnering with Snowflake on this killer feature.</p>]]></content>
        <author>
            <name>Anna Lee</name>
        </author>
        <author>
            <name>Mila Page</name>
        </author>
        <category label="iceberg" term="iceberg"/>
        <category label="catalogs" term="catalogs"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Make your AI better at data work with dbt's agent skills]]></title>
        <id>https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-agent-skills</id>
        <link href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-agent-skills"/>
        <updated>2026-02-05T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[We built a collection of Agent Skills to make coding agents better at using dbt projects and doing analytics work.]]></summary>
        <content type="html"><![CDATA[<p>Community-driven creation and curation of best practices is perhaps <em>the</em> driving factor behind dbt and analytics engineering’s rise - transferrable workflows and processes enable everyone to create and disseminate organizational knowledge. In the early days, <del>dbt Labs’</del> Fishtown Analytics’ <a href="https://github.com/dbt-labs/corp/blob/773079cc140e8636403771e0c9f56ab9be528597/dbt_style_guide.md" target="_blank" rel="noopener noreferrer">dbt_style_guide.md</a> contained foundational guidelines for anyone adopting the dbt viewpoint for the first time.</p>
<p>Today we released a collection of <a href="https://github.com/dbt-labs/dbt-agent-skills" target="_blank" rel="noopener noreferrer">dbt agent skills</a> so that <span>AI agents</span> (like Claude Code, OpenAI's Codex, Cursor, Factory or Kilo Code) can follow the same dbt best practices you would expect of any collaborator in your codebase. This matters because by extending their baseline capabilities, <strong>skills can transform generalist coding agents into highly capable data agents</strong>.</p>
<link href="/css/featherlight-styles.css" type="text/css" rel="stylesheet"><div class="
          docImage_EYbW
          
          
          
          
        " style="max-width:85%"><span><a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-agent-skills#" data-featherlight="/img/blog/2026-02-03-dbt-agent-skills/skills-blog-infographic.png"><img data-toggle="lightbox" alt="Diagram showing how dbt agent skills transform generalist coding agents into specialized data agents capable of analytics engineering, semantic layer definition, testing, debugging, natural language querying, and migration workflows" title="dbt agent skills allow you to transform generalist coding agents into highly capable data agents" src="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/img/blog/2026-02-03-dbt-agent-skills/skills-blog-infographic.png?v=2"></a></span><span class="title_aGrV">dbt agent skills allow you to transform generalist coding agents into highly capable data agents</span></div>
<p>These skills encapsulate a broad swathe of hard-won knowledge from the dbt Community and the dbt Labs Developer Experience team. Collectively, they represent dozens of hours of focused work by dbt experts, backed by years of using dbt.</p>
<link href="/css/featherlight-styles.css" type="text/css" rel="stylesheet"><div class="
          docImage_EYbW
          
          
          
          
        " style="max-width:85%"><span><a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-agent-skills#" data-featherlight="/img/blog/2026-02-03-dbt-agent-skills/with_skill.gif"><img data-toggle="lightbox" alt="A gif showing Claude using the analytics engineering skill to validate its work" title="With access to skills, agents like Claude take a systematic approach to tasks" src="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/img/blog/2026-02-03-dbt-agent-skills/with_skill.gif?v=2"></a></span><span class="title_aGrV">With access to skills, agents like Claude take a systematic approach to tasks</span></div>
<p>The ecosystem is rapidly evolving for both authors of skills and the agents that consume them. We believe these skills are very useful today, <em>and</em> that they will become more useful over the coming weeks and months as:</p>
<ul>
<li>skills become better embedded into agent workflows, particularly increasing the rate at which they select the right skills to use at the right time</li>
<li>wider community adoption and feedback improves the breadth and depth of available skills</li>
</ul>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="whats-included">What’s included<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-agent-skills#whats-included" class="hash-link" aria-label="Direct link to What’s included" title="Direct link to What’s included">​</a></h2>
<p>Our <a href="https://github.com/dbt-labs/dbt-agent-skills" target="_blank" rel="noopener noreferrer">agent skills repo</a> contains skills for:</p>
<ul>
<li><strong>Analytics engineering</strong>: Build and modify dbt models, write tests, explore data sources</li>
<li><strong>Semantic layer</strong>: Create metrics, dimensions, and semantic models with MetricFlow</li>
<li><strong>Platform operations</strong>: Troubleshoot job failures, configure the dbt MCP server</li>
<li><strong>Migration</strong>: Move projects from dbt Core to the dbt Fusion engine</li>
</ul>
<p>You’ll notice these skills vary in size of task and complexity. The primary <a href="https://github.com/dbt-labs/dbt-agent-skills/tree/main/skills/dbt/skills/using-dbt-for-analytics-engineering" target="_blank" rel="noopener noreferrer"><em>using dbt for analytics engineering</em> skill</a> contains information about the entire workflow loop for analytics engineering. Other skills are more focused and task dependent.</p>
<p>We plan to continue refining these and adding more skills over time. If there’s a skill that would be useful that you don’t see, please open an issue on the repo.</p>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="quickstart">Quickstart<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-agent-skills#quickstart" class="hash-link" aria-label="Direct link to Quickstart" title="Direct link to Quickstart">​</a></h2>
<h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="1-add-the-skills-to-your-agent">1. Add the skills to your agent<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-agent-skills#1-add-the-skills-to-your-agent" class="hash-link" aria-label="Direct link to 1. Add the skills to your agent" title="Direct link to 1. Add the skills to your agent">​</a></h3>
<p>In Claude Code, run these commands (one at a time):</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#d6deeb;--prism-background-color:#011627"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-bash codeBlock_qGQc thin-scrollbar" style="color:#d6deeb;background-color:#011627"><code class="codeBlockLines_p187"><span class="token-line" style="color:#d6deeb"><span class="token plain">/plugin marketplace </span><span class="token function" style="color:rgb(130, 170, 255)">add</span><span class="token plain"> dbt-labs/dbt-agent-skills</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#d6deeb;--prism-background-color:#011627"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-bash codeBlock_qGQc thin-scrollbar" style="color:#d6deeb;background-color:#011627"><code class="codeBlockLines_p187"><span class="token-line" style="color:#d6deeb"><span class="token plain">/plugin </span><span class="token function" style="color:rgb(130, 170, 255)">install</span><span class="token plain"> dbt@dbt-agent-marketplace</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>For agents other than Claude Code, use this command (<a href="https://nodejs.org/en/download" target="_blank" rel="noopener noreferrer">requires Node to be installed</a>):</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#d6deeb;--prism-background-color:#011627"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-bash codeBlock_qGQc thin-scrollbar" style="color:#d6deeb;background-color:#011627"><code class="codeBlockLines_p187"><span class="token-line" style="color:#d6deeb"><span class="token plain">npx skills </span><span class="token function" style="color:rgb(130, 170, 255)">add</span><span class="token plain"> dbt-labs/dbt-agent-skills </span><span class="token parameter variable" style="color:rgb(214, 222, 235)">--global</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>or just manually copy the files you want into the <a href="https://github.com/vercel-labs/skills?tab=readme-ov-file#supported-agents" target="_blank" rel="noopener noreferrer">correct path for your agent</a>.</p>
<h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="2-start-a-new-agent-session">2. Start a new agent session<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-agent-skills#2-start-a-new-agent-session" class="hash-link" aria-label="Direct link to 2. Start a new agent session" title="Direct link to 2. Start a new agent session">​</a></h3>
<p>Restart your terminal to make sure the new skills are detected.</p>
<h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="3-try-it-yourself">3. Try it yourself<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-agent-skills#3-try-it-yourself" class="hash-link" aria-label="Direct link to 3. Try it yourself" title="Direct link to 3. Try it yourself">​</a></h3>
<p>Try giving an instruction like:</p>
<ul>
<li>Plan and build models for my new HubSpot source tables</li>
<li>Work out why my <code>dbt build</code> just failed</li>
<li>Write unit tests based on the requirements in this GitHub issue, then create a new model that passes</li>
<li>Update <code>fct_transactions</code> to become a semantic model</li>
<li>Is there a difference in bounce rate for free vs paid email domains?</li>
</ul>
<p>We focused on tasks that are either common (daily model building, debugging) or complex (semantic layer setup, unit testing edge cases). Each skill contains high-signal knowledge, and has been validated in real-world testing and against <span>ADE-bench</span>.</p>
<p>If you just want to get started today, you can stop reading now. But there’s a whole lot to say about what skills are, why they’re useful and how we expect them to plug into the dbt workflows of today and tomorrow.</p>
<div class="theme-admonition theme-admonition-note admonition_xJq3 alert alert--secondary"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>note</div><div class="admonitionContent_BuS1"><p>Normal cautions around agentic coding apply. Please take appropriate safeguards, particularly when working with production or sensitive data.</p></div></div>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="so-what-is-a-skill-anyway">So what is a skill, anyway?<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-agent-skills#so-what-is-a-skill-anyway" class="hash-link" aria-label="Direct link to So what is a skill, anyway?" title="Direct link to So what is a skill, anyway?">​</a></h2>
<p>You can think of skills as bundles of prompts (and scripts) which LLMs can dynamically string together to gain context or expertise on a given task.</p>
<p>In some ways, a skill is very simple - it’s a markdown file with a predefined structure. The venerable <code>dbt_style_guide.md</code> of yore would fit right in! It has a bunch of bulleted instructions, some sample code, and links out to other resources when necessary; the new Skills format does the same things. Anthropic introduced Skills in October 2025, and they are now an open standard adopted by <a href="https://github.com/vercel-labs/skills?tab=readme-ov-file#supported-agents" target="_blank" rel="noopener noreferrer">30+ agents</a>.</p>
<p>A better question than <em>what</em> might be <em>why</em>. From the <a href="https://agentskills.io/home" target="_blank" rel="noopener noreferrer">agent skills site</a>:</p>
<blockquote>
<p>Agents are increasingly capable, but often don’t have the context they need to do real work reliably. Skills solve this by giving agents access to procedural knowledge and company-, team-, and user-specific context they can load on demand.</p>
</blockquote>
<p>Here’s an <a href="https://claude.com/blog/equipping-agents-for-the-real-world-with-agent-skills" target="_blank" rel="noopener noreferrer">example skill from Anthropic</a>:</p>
<link href="/css/featherlight-styles.css" type="text/css" rel="stylesheet"><div class="
          docImage_EYbW
          
          
          
          
        " style="max-width:85%"><span><a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-agent-skills#" data-featherlight="/img/blog/2026-02-03-dbt-agent-skills/anthropic-skills-architecture.png"><img data-toggle="lightbox" alt="Anthropic’s diagram showing how agent skills use progressive disclosure with YAML frontmatter, markdown content, and reference files" title="An example SKILL.md file for working with PDFs, which also contains references to more complex workflows to load on-demand" src="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/img/blog/2026-02-03-dbt-agent-skills/anthropic-skills-architecture.png?v=2"></a></span><span class="title_aGrV">An example SKILL.md file for working with PDFs, which also contains references to more complex workflows to load on-demand</span></div>
<h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="how-do-skills-interact-with-mcp">How do skills interact with MCP?<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-agent-skills#how-do-skills-interact-with-mcp" class="hash-link" aria-label="Direct link to How do skills interact with MCP?" title="Direct link to How do skills interact with MCP?">​</a></h3>
<p>Another common question is how skills differ from MCP servers, and whether both are necessary.</p>
<ul>
<li>MCP is how you provide access to tools (especially remote tools requiring authentication)</li>
<li>Skills are how you provide context and knowledge around using those tools</li>
</ul>
<p>dbt Agent skills and the <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/introducing-dbt-mcp-server">dbt MCP server</a> are <em>complementary</em>, but you don’t have to use both to get value.</p>
<p>Consider the PDF example. Working with PDF files doesn’t require a MCP server, because the editing library can be installed locally. But you want that library to be used in a consistent way instead of the LLM inventing something from first principles every time.</p>
<p>So then why does the dbt MCP also have tools that call into the CLI? For interfaces that support MCP but not skills, it’s helpful to bake the <em>specific way the CLI commands are called</em> into the MCP server, but this is an open question and something we’re watching closely.</p>
<h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="from-generalist-to-specialist">From generalist to specialist<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-agent-skills#from-generalist-to-specialist" class="hash-link" aria-label="Direct link to From generalist to specialist" title="Direct link to From generalist to specialist">​</a></h3>
<p>To summarize, the best way to think of skills is as a layered training manual. If you took a very smart generalist off the street, what would they need to be able to use and implement <em>your organization's workflows?</em></p>
<link href="/css/featherlight-styles.css" type="text/css" rel="stylesheet"><div class="
          docImage_EYbW
          
          
          
          
        " style="max-width:85%"><span><a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-agent-skills#" data-featherlight="/img/blog/2026-02-03-dbt-agent-skills/skills-blog-diagram.png"><img data-toggle="lightbox" alt="A pyramid diagram showing three layers: Coding Agent at the base (takes autonomous actions, runs dbt commands, and looks up docs), dbt best practice skills in the middle (knows dbt best practices and workflows), and Project skills at the top (knows workflows unique to your team and data model)" title="Skills provide layered context that builds on an agent's baseline capabilities" src="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/img/blog/2026-02-03-dbt-agent-skills/skills-blog-diagram.png?v=2"></a></span><span class="title_aGrV">Skills provide layered context that builds on an agent's baseline capabilities</span></div>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="why-skills-matter">Why skills matter<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-agent-skills#why-skills-matter" class="hash-link" aria-label="Direct link to Why skills matter" title="Direct link to Why skills matter">​</a></h2>
<h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="skills-allow-you-to-embed-complex-process-knowledge-that-is-non-obvious-to-agents">Skills allow you to embed complex process knowledge that is non-obvious to agents<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-agent-skills#skills-allow-you-to-embed-complex-process-knowledge-that-is-non-obvious-to-agents" class="hash-link" aria-label="Direct link to Skills allow you to embed complex process knowledge that is non-obvious to agents" title="Direct link to Skills allow you to embed complex process knowledge that is non-obvious to agents">​</a></h3>
<p>Any experienced dbt practitioner will have a number of intuitions when working with a dbt project:</p>
<ul>
<li>You want to poke around a bit and get a sense of the schema and underlying data before making any changes. Read some docs, run a couple of <code>dbt show</code> queries, that sort of thing.</li>
<li>If you’re modifying an existing model, you need to look at the underlying data and get a sense of what columns live in upstream data sources.</li>
<li>After making a new model or modifying one, you need to look at the data again, as well as run summary/aggregate statistics to see if it matches your expected shape and output</li>
</ul>
<p>The current generation of coding agents tends to not do these things by default. Skills fix that by including broad dbt best practices like the ones above, but they can also provide very in-depth and nuanced guidance through supplemental reference materials, such as:</p>
<ul>
<li>Warehouse-specific configurations, like avoiding full table scans on BigQuery when discovering data</li>
<li>Variations based on the specific dbt version or engine you’re using; <code>dbt compile</code> can <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/the-levels-of-sql-comprehension">detect many SQL errors</a> when invoked from the dbt Fusion engine, but dbt Core needs to run <code>dbt build</code> for the same result.</li>
</ul>
<p>Skills can also evolve at a faster pace than frontier AI model releases, making it easier to update guidance and adapt to changes in the dbt authoring layer. We recently <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/modernizing-the-semantic-layer-spec">revamped the authoring experience for semantic models</a>; by including a skill that knows about the new syntax, we can stop your agent from using the old syntax even though that’s the majority of training data online.</p>
<h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="skills-protect-against-plausible-but-incorrect-output">Skills protect against plausible but incorrect output<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-agent-skills#skills-protect-against-plausible-but-incorrect-output" class="hash-link" aria-label="Direct link to Skills protect against plausible but incorrect output" title="Direct link to Skills protect against plausible but incorrect output">​</a></h3>
<p>If you ask an LLM to add some tests to your model, it might add an <code>accepted values</code> test. dbt’s documentation on <code>accepted_values</code> tests <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/reference/resource-properties/data-tests#accepted_values">contains an example</a> saying that the right values on an <code>order_status</code> column are <code>['placed', 'shipped', 'completed', 'returned']</code>, and we’ve seen some models replicate this or otherwise hallucinate potential column values.</p>
<p>With a skill, you can instruct the agent to <strong>preview the data before writing tests</strong> to ensure that the output matches the real data in your warehouse.</p>
<h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="skills-allow-you-to-give-opinionated-guidance-to-agents">Skills allow you to give opinionated guidance to agents<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-agent-skills#skills-allow-you-to-give-opinionated-guidance-to-agents" class="hash-link" aria-label="Direct link to Skills allow you to give opinionated guidance to agents" title="Direct link to Skills allow you to give opinionated guidance to agents">​</a></h3>
<p>Beyond global best practices, there are also a number of opinionated decisions inside of a given team’s dbt project:</p>
<ul>
<li>What types of data tests should I have on my models?</li>
<li>When should I use the Semantic Layer vs. SQL for natural language questions?</li>
<li>How should the project be structured (stg/int/mart? Medallion? Data vault?)</li>
</ul>
<p>Our current skills are only semi-opinionated - they have opinions on how and where you should apply your data tests but not on whether you should use dbt’s recommended project structure or style guide. In the future we anticipate that we will release first party opinionated guides on project and code structure and that there will be a thriving ecosystem of opinionated community-sourced skills on different dimensions of data work.</p>
<h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="skills-allow-you-to-give-non-public-information-to-agents">Skills allow you to give non-public information to agents<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-agent-skills#skills-allow-you-to-give-non-public-information-to-agents" class="hash-link" aria-label="Direct link to Skills allow you to give non-public information to agents" title="Direct link to Skills allow you to give non-public information to agents">​</a></h3>
<p>In addition to adopting our skills, you should add some of your own.</p>
<p>Taking a smart generalist across all disciplines and turning them into a smart generalist with a specialization in dbt still isn’t enough. They also need to become a specialist in the way your company does data.</p>
<p>Obviously we can’t include those in our general best practices skills, but this is where the composability of skills comes in. You can add context about your company, your data, the specific ins and outs and nuances of interacting with your systems, and expect it to augment what we provide.</p>
<p>Examples of questions you might like to answer in your skills:</p>
<ul>
<li>Have any default macros been overridden in my organization’s project?</li>
<li>What is my organization’s cross-project or cross-platform mesh strategy?</li>
<li>What partitioning rules should be applied to new models for a given usage pattern?</li>
</ul>
<p>More to come soon on how we might support org level skills within dbt projects.</p>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="how-we-validated-the-dbt-agent-skills">How we validated the dbt Agent Skills<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-agent-skills#how-we-validated-the-dbt-agent-skills" class="hash-link" aria-label="Direct link to How we validated the dbt Agent Skills" title="Direct link to How we validated the dbt Agent Skills">​</a></h2>
<p>It can be challenging to assess the performance of AI workflows. There are many different ways to do this and all of them are imperfect, so we have settled on a multilayered strategy for ensuring our agent skills behave the way we want them to.</p>
<h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="careful-expert-generation-and-curation-of-skills">Careful expert generation and curation of skills<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-agent-skills#careful-expert-generation-and-curation-of-skills" class="hash-link" aria-label="Direct link to Careful expert generation and curation of skills" title="Direct link to Careful expert generation and curation of skills">​</a></h3>
<p>While we <em>did</em> have some LLM assistance in generating some of the skills, these are very much not "oneshotted outputs". Each skill represents hours of crafting, reviewing and refining by world class dbt experts to ensure that our knowledge has been accurately encoded into the skills. Data work has a <em>lot</em> of tacit knowledge and edge cases, and this is where skills really shine.</p>
<h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="hands-on-testing-of-each-skill-in-real-life-examples">Hands-on testing of each skill in real life examples<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-agent-skills#hands-on-testing-of-each-skill-in-real-life-examples" class="hash-link" aria-label="Direct link to Hands-on testing of each skill in real life examples" title="Direct link to Hands-on testing of each skill in real life examples">​</a></h3>
<p>Nothing beats hands-on usage and so we’ve tested each skill to see how it performs in real use cases. This has helped us tune the performance and identify non-obvious gaps in our instructions.</p>
<p>We were particularly thrilled when we asked the agent to make performance recommendations on one of the largest tables in our dbt project, with and without the skill. While both results gave plausible recommendations, the recommendations with the skill were more tailored and relevant to our use case as determined by our internal data team.</p>
<link href="/css/featherlight-styles.css" type="text/css" rel="stylesheet"><div class="
          docImage_EYbW
          
          
          
          
        " style="max-width:85%"><span><a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-agent-skills#" data-featherlight="/img/blog/2026-02-03-dbt-agent-skills/skills-validation-feedback.png"><img data-toggle="lightbox" alt="A Slack screenshot from @brandon, who says 'that version excites me much, much more. the recommendations on incremental filtering on all refs, pre-aggregated int models etc. i think would make a huge impact.'" title="" src="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/img/blog/2026-02-03-dbt-agent-skills/skills-validation-feedback.png?v=2"></a></span></div>
<h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="custom-suite-for-ab-testing-skills">Custom suite for A/B testing skills<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-agent-skills#custom-suite-for-ab-testing-skills" class="hash-link" aria-label="Direct link to Custom suite for A/B testing skills" title="Direct link to Custom suite for A/B testing skills">​</a></h3>
<p>We developed a <a href="https://github.com/dbt-labs/dbt-agent-skills/tree/main/evals" target="_blank" rel="noopener noreferrer">system for rapidly comparing different tool combinations</a> (MCP + skills, skills alone, no tools) to understand how they changed an agent’s output.</p>
<p>This library allows testing how variations of skills perform for a given scenario and reviewing in detail the skills and tools called by the agent.</p>
<p>We provide context to Claude Code (e.g. a dbt project or some YAML files) and we ask it to solve a problem with different setups:</p>
<ul>
<li>with different variations of a skill</li>
<li>with or without a MCP server connected</li>
<li>explicitly prompting the agent to use a skill, or leaving it to discover it solo</li>
</ul>
<p>We can then either manually compare the conversations (which skills were called, what output was produced), or ask Claude Code to rate the different runs automatically.</p>
<p>One thing we discovered in this process is that Claude is much less willing to use skills in "headless" CLI invocations than "interactive" ones where a user is talking back and forth. Because of this, we felt comfortable including the explicit prompt in benchmarking tasks.</p>
<h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="benchmarking-against-ade-bench">Benchmarking against ADE-bench<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-agent-skills#benchmarking-against-ade-bench" class="hash-link" aria-label="Direct link to Benchmarking against ADE-bench" title="Direct link to Benchmarking against ADE-bench">​</a></h3>
<p>We also ran through the <span>ADE-bench</span> tasks to assess performance with and without skills. While not every skill has corresponding tasks in the benchmark (yet!), this provides helpful signal, particularly on the primary analytics engineering skill.</p>
<p>We saw modest improvements in performance on the benchmark with Skills, rising from a 56% accuracy rate without skills to a 58.5% accuracy rate with Skills. But the bigger story is not the headline numbers, but the individual tasks that were solved with skills that previously had 0% success rates.</p>
<p>Notably, we found <strong>significant benefits in tasks which require iterative work</strong> on top of a dbt DAG, which is one of the most common failure points we've experienced in using coding agents with dbt.</p>
<div style="display:grid;grid-template-columns:repeat(auto-fit, minmax(300px, 1fr));gap:1rem"><div style="text-align:center"><p><strong>Without skills</strong></p><p><img decoding="async" loading="lazy" alt="Without skills, agents may skip important validation steps" src="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/assets/images/without_skill-da56373701544fd8711c725d25d95011.gif" width="1800" height="1000" class="img_ev3q"></p></div><div style="text-align:center"><p><strong>With skills</strong></p><p><img decoding="async" loading="lazy" alt="With access to skills, agents take a systematic approach to tasks" src="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/assets/images/with_skill-b62eb0689de0bb0352a714958a579f2e.gif" width="1800" height="1000" class="img_ev3q"></p></div></div>
<p>For example, when asked to <a href="https://github.com/dbt-labs/ade-bench/blob/main/tasks/airbnb007/task.yaml" target="_blank" rel="noopener noreferrer">produce multiple models based on their schema.yml definition</a>, the baseline agent created 6 models at once and declared victory. The skill-using agent worked iteratively, and successfully completed the task every time.</p>
<p>On the other hand, encouraging DRY principles led to the skill-using agent intermittently reusing a column with a logic bug in <a href="https://github.com/dbt-labs/ade-bench/blob/main/tasks/f1009/task.yaml" target="_blank" rel="noopener noreferrer">this task</a>, where the baseline agent noticed and corrected the bug.</p>
<h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="where-there-are-gaps">Where there are gaps<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-agent-skills#where-there-are-gaps" class="hash-link" aria-label="Direct link to Where there are gaps" title="Direct link to Where there are gaps">​</a></h3>
<p>Today, skill loading can be a little hit-and-miss. As with everything in AI, things are moving fast, and skills are seeing widespread adoption, so we don’t think that’s going to be a long term issue. We’d also love to see stronger and more reliable cross-skill referencing, such as <a href="https://github.com/agentskills/agentskills/issues/90" target="_blank" rel="noopener noreferrer">what’s described here</a>.</p>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="again-you-should-go-try-this-yourself">Again: you should go try this yourself<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-agent-skills#again-you-should-go-try-this-yourself" class="hash-link" aria-label="Direct link to Again: you should go try this yourself" title="Direct link to Again: you should go try this yourself">​</a></h2>
<p><a href="https://github.com/dbt-labs/dbt-agent-skills" target="_blank" rel="noopener noreferrer">Here’s the repo</a>, with installation instructions in the readme.</p>
<p>Agent skills have tremendous bang-for-buck for procedural tasks, especially considering how easily you can get started. We’re excited to see many people from across the Community trying them on real-world workflows, and building new skills of their own.</p>
<p>We’re also exploring ways to enable tighter integration between dbt and agent skills, as well as making it easier to manage custom skills for your specific dbt project and data.</p>
<p>The best way to stay involved is to share what you're discovering in <a href="https://getdbt.slack.com/archives/C0A1MRWEH8C/p1769918756796829" target="_blank" rel="noopener noreferrer">#topic-agentic-analytics</a> on Slack or to open up issues on the GitHub repo.</p>]]></content>
        <author>
            <name>Joel Labes</name>
        </author>
        <author>
            <name>Jason Ganz</name>
        </author>
        <category label="ai" term="ai"/>
        <category label="data_ecosystem" term="data_ecosystem"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Modernizing the Semantic Layer Spec]]></title>
        <id>https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/modernizing-the-semantic-layer-spec</id>
        <link href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/modernizing-the-semantic-layer-spec"/>
        <updated>2026-01-21T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Learn about the new semantic layer specification and how it improves data modeling.]]></summary>
        <content type="html"><![CDATA[<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="new-engine-who-dis">New engine, who dis?<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/modernizing-the-semantic-layer-spec#new-engine-who-dis" class="hash-link" aria-label="Direct link to New engine, who dis?" title="Direct link to New engine, who dis?">​</a></h2>
<p>It’s unlikely that anyone reading this blog has not heard about the new dbt Fusion engine — it’s been the talk of the data town since last January, culminating in Elias’s legendary live Coalesce 2025 demo of the incredible capabilities that native SQL comprehension in dbt can unlock. If you attended Coalesce, or have upgraded your project to Fusion already, you’ve likely also heard about the changes we’ve made to the authoring layer of dbt (the literal code you write in your project). As part of the major version upgrade, we took the opportunity to simplify + standardize the configuration language of dbt to be built to scale as we enter the next era of analytics engineering.</p>
<p>In particular, we wanted to reevaluate how metrics are defined in the dbt Semantic Layer. We’ve heard from numerous community members over the years that defining metrics was <em>just plain hard</em>. In conversation with internal + external users and our newest pals from SDF, we’ve come up with a redesigned YAML spec that is simpler, more integrated to the dbt configuration experience we’ve come to know and love, and built for the future.</p>
<h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="whats-changing">What’s changing?<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/modernizing-the-semantic-layer-spec#whats-changing" class="hash-link" aria-label="Direct link to What’s changing?" title="Direct link to What’s changing?">​</a></h3>
<p>There are three major updates to the structure of semantic modeling in dbt:</p>
<ul>
<li><strong>Measures → Metrics:</strong> Measures are removed from the authorship spec. Simple metrics now can include aggregations and expressions and are the primary building block for more complex metrics.</li>
<li><strong>Reducing nesting:</strong> We removed as much deep dictionary nesting as possible to simplify the look and feel of the code, and renamed keys to more directly describe their behavior.</li>
<li><strong>Standardizing on models YAML entries:</strong> Semantic annotations are embedded within the model’s YAML entry to remove the need to manage many YAML entries across many files to enrich your models with semantic metadata.</li>
</ul>
<div style="display:grid;grid-template-columns:repeat(auto-fit, minmax(300px, 1fr));gap:16px;margin:0 -20px 20px -20px;max-width:calc(100% + 40px)"><div style="padding:0 12px"><h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="legacy-implementation">Legacy implementation<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/modernizing-the-semantic-layer-spec#legacy-implementation" class="hash-link" aria-label="Direct link to Legacy implementation" title="Direct link to Legacy implementation">​</a></h3><div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#d6deeb;--prism-background-color:#011627"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-yaml codeBlock_qGQc thin-scrollbar" style="color:#d6deeb;background-color:#011627"><code class="codeBlockLines_p187"><span class="token-line" style="color:#d6deeb"><span class="token key atrule" style="color:rgb(255, 203, 139)">models</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain"> </span><span class="token key atrule" style="color:rgb(255, 203, 139)">name</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> customers</span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token key atrule" style="color:rgb(255, 203, 139)">description</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> Customer overview data mart</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> offering key details for each unique customer. One row per customer.</span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token key atrule" style="color:rgb(255, 203, 139)">columns</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain"> </span><span class="token key atrule" style="color:rgb(255, 203, 139)">name</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> customer_id</span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">        </span><span class="token key atrule" style="color:rgb(255, 203, 139)">description</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> The unique key of the orders mart.</span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain"> </span><span class="token key atrule" style="color:rgb(255, 203, 139)">name</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> first_ordered_at</span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">        </span><span class="token key atrule" style="color:rgb(255, 203, 139)">description</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> The timestamp when a customer placed their first order.</span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token key atrule" style="color:rgb(255, 203, 139)">semantic_models</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain"> </span><span class="token key atrule" style="color:rgb(255, 203, 139)">name</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token key atrule" style="color:rgb(255, 203, 139)">customers</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token key atrule" style="color:rgb(255, 203, 139)">model</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> ref('customers')</span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token key atrule" style="color:rgb(255, 203, 139)">description</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> Semantic Model for Customers</span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token key atrule" style="color:rgb(255, 203, 139)">defaults</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">      </span><span class="token key atrule" style="color:rgb(255, 203, 139)">agg_time_dimension</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> first_ordered_at</span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token key atrule" style="color:rgb(255, 203, 139)">entities</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain"> </span><span class="token key atrule" style="color:rgb(255, 203, 139)">name</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> customer</span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">        </span><span class="token key atrule" style="color:rgb(255, 203, 139)">type</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> primary</span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">        </span><span class="token key atrule" style="color:rgb(255, 203, 139)">expr</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> customer_id</span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">     </span><span class="token key atrule" style="color:rgb(255, 203, 139)">dimensions</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">       </span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain"> </span><span class="token key atrule" style="color:rgb(255, 203, 139)">name</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> first_ordered_at</span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">         </span><span class="token key atrule" style="color:rgb(255, 203, 139)">type</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> time</span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">         </span><span class="token key atrule" style="color:rgb(255, 203, 139)">type_params</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">           </span><span class="token key atrule" style="color:rgb(255, 203, 139)">time_granularity</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> day</span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">     </span><span class="token key atrule" style="color:rgb(255, 203, 139)">measures</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">       </span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain"> </span><span class="token key atrule" style="color:rgb(255, 203, 139)">name</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> lifetime_spend_pretax</span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">         </span><span class="token key atrule" style="color:rgb(255, 203, 139)">agg</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> sum</span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain"> </span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain"> </span><span class="token key atrule" style="color:rgb(255, 203, 139)">metrics</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">   </span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain"> </span><span class="token key atrule" style="color:rgb(255, 203, 139)">name</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> lifetime_spend_pretax</span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">     </span><span class="token key atrule" style="color:rgb(255, 203, 139)">type</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> simple</span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">     </span><span class="token key atrule" style="color:rgb(255, 203, 139)">description</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> Customer's lifetime spend before tax</span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">     </span><span class="token key atrule" style="color:rgb(255, 203, 139)">label</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> LTV Pre</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">tax</span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">     </span><span class="token key atrule" style="color:rgb(255, 203, 139)">type_params</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">        </span><span class="token key atrule" style="color:rgb(255, 203, 139)">measure</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">          </span><span class="token key atrule" style="color:rgb(255, 203, 139)">name</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> lifetime_spend_pretax</span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain"> </span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div></div><div style="padding:0 12px"><h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="new-implementation">New implementation<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/modernizing-the-semantic-layer-spec#new-implementation" class="hash-link" aria-label="Direct link to New implementation" title="Direct link to New implementation">​</a></h3><div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#d6deeb;--prism-background-color:#011627"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-yaml codeBlock_qGQc thin-scrollbar" style="color:#d6deeb;background-color:#011627"><code class="codeBlockLines_p187"><span class="token-line" style="color:#d6deeb"><span class="token key atrule" style="color:rgb(255, 203, 139)">models</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain"> </span><span class="token key atrule" style="color:rgb(255, 203, 139)">name</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> customers</span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">    </span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># enable semantic modeling on this model</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token key atrule" style="color:rgb(255, 203, 139)">semantic_model</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">      </span><span class="token key atrule" style="color:rgb(255, 203, 139)">enabled</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token boolean important" style="color:rgb(255, 88, 116)">true</span><span class="token plain"> </span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">    </span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># set default aggregation time dimension as a model property</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token key atrule" style="color:rgb(255, 203, 139)">agg_time_dimension</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> first_ordered_at</span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">    </span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token key atrule" style="color:rgb(255, 203, 139)">description</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> Customer overview data mart</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> offering key details for each unique customer. One row per customer.</span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">    </span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token key atrule" style="color:rgb(255, 203, 139)">columns</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain"> </span><span class="token key atrule" style="color:rgb(255, 203, 139)">name</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> customer_id</span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">        </span><span class="token key atrule" style="color:rgb(255, 203, 139)">description</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> The unique key of the orders mart.</span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">        </span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># annotate column as a primary entity</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">        </span><span class="token key atrule" style="color:rgb(255, 203, 139)">entity</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">          </span><span class="token key atrule" style="color:rgb(255, 203, 139)">name</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> customer</span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">          </span><span class="token key atrule" style="color:rgb(255, 203, 139)">type</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> primary</span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">          </span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain"> </span><span class="token key atrule" style="color:rgb(255, 203, 139)">name</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> first_ordered_at</span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">        </span><span class="token key atrule" style="color:rgb(255, 203, 139)">description</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> The timestamp when a customer placed their first order.</span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">        </span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># annotate column as a time dimension</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">        </span><span class="token key atrule" style="color:rgb(255, 203, 139)">granularity</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> day</span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">        </span><span class="token key atrule" style="color:rgb(255, 203, 139)">dimension</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">          </span><span class="token key atrule" style="color:rgb(255, 203, 139)">type</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> time</span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">          </span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># define simple metric directly within the model's YAML</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token key atrule" style="color:rgb(255, 203, 139)">metrics</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain"> </span><span class="token key atrule" style="color:rgb(255, 203, 139)">name</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> lifetime_spend_pretax</span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">        </span><span class="token key atrule" style="color:rgb(255, 203, 139)">type</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> simple</span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">        </span><span class="token key atrule" style="color:rgb(255, 203, 139)">description</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> Customer's lifetime spend before tax</span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">        </span><span class="token key atrule" style="color:rgb(255, 203, 139)">label</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> LTV Pre</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">tax</span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">        </span><span class="token key atrule" style="color:rgb(255, 203, 139)">agg</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> sum</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div></div></div>
<p>This has a few clear benefits:</p>
<ul>
<li><strong>DRYer code:</strong> Semantic annotations are now alongside the model’s YAML entry, reducing duplicative work. Now, if a column within the model is a dimension or entity, you can configure it as such. The properties of the column, like its description, are then reflected as the description of the dimension / entity!</li>
<li><strong>Tidier YAML:</strong> A tidier metric entry is easier to write, easier to read, and easier to share context across your data team. Maintenance of metric code should be as easy as possible!</li>
</ul>
<h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="is-this-the-osi-spec">Is this the OSI spec?<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/modernizing-the-semantic-layer-spec#is-this-the-osi-spec" class="hash-link" aria-label="Direct link to Is this the OSI spec?" title="Direct link to Is this the OSI spec?">​</a></h3>
<p>You may have heard some buzz that dbt joined the industry initiative called the <a href="https://www.snowflake.com/en/blog/open-semantic-interchange-ai-standard/" target="_blank" rel="noopener noreferrer">Open Semantic Interchange</a>, working with partners like Snowflake and Tableau to create an open standard for semantic metadata. This is not the OSI Spec! This is an update to the existing dbt Semantic Layer spec, designed to make it easier for dbt users to define and manage their metrics. However, we are actively exploring how we can align with the OSI spec in the future, and we see this as a step towards that goal.</p>
<h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="get-started-today">Get started today<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/modernizing-the-semantic-layer-spec#get-started-today" class="hash-link" aria-label="Direct link to Get started today" title="Direct link to Get started today">​</a></h3>
<p>This new spec is <strong>live on the Fusion engine today.</strong> If you’ve <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/guides/upgrade-to-fusion?step=1">migrated</a> onto the engine, and are curious about getting started with the dbt Semantic Layer, <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/docs/build/latest-metrics-spec">check out our docs</a> and get started defining your metrics! This new spec will also be released to dbt Core in version 1.12, coming in the near future. dbt platform users on the dbt Core engine will be able to migrate to the new spec as soon as they upgrade to the Latest dbt version!</p>
<p>Additionally, if you’re an existing user of the semantic layer, our <a href="https://github.com/dbt-labs/dbt-autofix" target="_blank" rel="noopener noreferrer"><code>dbt-autofix</code> script</a> now has support for migrating from the legacy metrics implementation to the new one! Simply run <code>dbt-autofix deprecations --semantic-layer</code>, locally or in dbt Studio on the platform, and the vast majority of the code will be migrated automatically!</p>
<p>We’re eager for feedback! Reach out in dbt Community Slack in the <a href="https://getdbt.slack.com/archives/C046L0VTVR6" target="_blank" rel="noopener noreferrer"><code>#dbt-semantic-layer</code> channel</a> and let us know how your migration / onboarding experience goes!</p>]]></content>
        <author>
            <name>Dave Connors</name>
        </author>
        <category label="ai" term="ai"/>
        <category label="data ecosystem" term="data ecosystem"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Building the Remote dbt MCP Server]]></title>
        <id>https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/building-the-remote-dbt-mcp-server</id>
        <link href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/building-the-remote-dbt-mcp-server"/>
        <updated>2025-08-26T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Learn about the new remote dbt MCP server, how it was built, and how to use it to build agents.]]></summary>
        <content type="html"><![CDATA[<p>In April, we released the local <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/introducing-dbt-mcp-server">dbt MCP (Model Context Protocol) server</a> as an open source project to connect AI agents and LLMs with direct, governed access to trusted dbt assets. The dbt MCP server provides a <a href="https://docs.anthropic.com/en/docs/mcp" target="_blank" rel="noopener noreferrer">universal, open standard</a> for bridging AI systems with your structured context that keeps your agents accurate, governed, and trustworthy. Learn more in <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/docs/dbt-ai/about-mcp">About dbt Model Context Protocol</a>.</p>
<p>Since releasing the local dbt MCP server, the dbt community has been applying it in incredible ways including agentic conversational analytics, data catalog exploration, and dbt project refactoring. However, a key piece of feedback we received from AI engineers was that the local dbt MCP server isn’t easy to deploy or host for multi-tenanted workloads, making it difficult to build applications on top of the dbt MCP server.</p>
<p>This is why we are excited to announce a new way to integrate with dbt MCP: <strong>the remote dbt MCP server</strong>. The remote dbt MCP server doesn’t require installing dependencies or running the dbt MCP server in your infrastructure, making it easier than ever to build and run agents. It is <strong>available today in public beta</strong> for users with dbt Starter, Enterprise, or Enterprise+ plans, ready for you to start building AI-powered applications.</p>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="what-is-the-remote-dbt-mcp-server-">What is the Remote dbt MCP Server? <a href="https://www.getdbt.com/pricing" target="_blank" rel="noopener noreferrer" class="planPill_aqx1 plan-pill" style="background-color:#E5E7EB;color:#030711;cursor:pointer;transition:background-color 0.2s ease, transform 0.2s ease, text-decoration 0.2s ease;text-decoration:none;font-size:0.82rem" title="Go to https://www.getdbt.com/pricing">Starter</a><a href="https://www.getdbt.com/pricing" target="_blank" rel="noopener noreferrer" class="planPill_aqx1 plan-pill" style="background-color:#E5E7EB;color:#030711;cursor:pointer;transition:background-color 0.2s ease, transform 0.2s ease, text-decoration 0.2s ease;text-decoration:none;font-size:0.82rem" title="Go to https://www.getdbt.com/pricing">Enterprise</a><a href="https://www.getdbt.com/pricing" target="_blank" rel="noopener noreferrer" class="planPill_aqx1 plan-pill" style="background-color:#E5E7EB;color:#030711;cursor:pointer;transition:background-color 0.2s ease, transform 0.2s ease, text-decoration 0.2s ease;text-decoration:none;font-size:0.82rem" title="Go to https://www.getdbt.com/pricing">Enterprise +</a><a href="https://docs.getdbt.com/docs/dbt-versions/product-lifecycles" target="_blank" rel="noopener noreferrer" class="lifecycle_J1Zi lifecycle" style="background-color:#bab2ff;color:#030711;cursor:pointer;transition:background-color 0.2s ease, transform 0.2s ease, text-decoration 0.2s ease;text-decoration:none;font-size:0.82rem" title="Go to https://docs.getdbt.com/docs/dbt-versions/product-lifecycles">Beta</a><a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/building-the-remote-dbt-mcp-server#what-is-the-remote-dbt-mcp-server-" class="hash-link" aria-label="Direct link to what-is-the-remote-dbt-mcp-server-" title="Direct link to what-is-the-remote-dbt-mcp-server-">​</a></h2>
<p>Commonly, agents and MCP servers run locally on your computer, but local-first agents are limited in the type of applications that can be built. With remote MCP, new experiences are possible. For instance, remote MCP enables server-side agents to perform long-running tasks, be shared across an organization, and be accessed through web applications -- all experiences that are far more difficult (or impossible) in a local agent architecture.</p>
<p>The remote dbt MCP server brings <strong>structured, governed context</strong> to these experiences and enables you to build innovative data applications on top of them. The remote dbt MCP server makes it possible for your agent to answer business questions with the <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/docs/use-dbt-semantic-layer/dbt-sl">dbt Semantic Layer</a>, discover data assets with the <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/docs/dbt-apis/discovery-api">dbt Discovery API</a>, and run natural-language queries with SQL tools. Check out our docs <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/docs/dbt-ai/about-mcp">here</a> to learn about the full list of supported tools. These capabilities are easy to integrate in various platforms with the standardized MCP specification.</p>
<p>The remote dbt MCP server is great for application builders, but there are still times when you would want to run the dbt MCP server locally. Specifically, <strong>if you are using a local coding agent like Cursor or Claude Code, we recommend the local dbt MCP server.</strong> This ensures that the code you are writing locally matches what the agent has access to.</p>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="the-remote-dbt-mcp-server-architecture">The Remote dbt MCP Server Architecture<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/building-the-remote-dbt-mcp-server#the-remote-dbt-mcp-server-architecture" class="hash-link" aria-label="Direct link to The Remote dbt MCP Server Architecture" title="Direct link to The Remote dbt MCP Server Architecture">​</a></h2>
<p>Hosting your own remote MCP server is non-trivial. While a local MCP server only has to consider a single tenant experience, remote servers need to manage concurrent connections from multiple different users as well as the deployment and maintenance of the server and infrastructure. Additionally, connections need to be securely authenticated and isolated from each other. The latest updates to the MCP spec provides a new way to communicate with MCP servers, <a href="https://modelcontextprotocol.io/specification/2025-06-18/basic/transports" target="_blank" rel="noopener noreferrer">Streamable HTTP</a>, allowing for stateless remote connections with agents. Streamable HTTP makes things easier but there is still a high lift for most data teams to deploy an MCP server. With the remote dbt MCP server, we handle all of this complexity so, if you are building an agentic application, all you need to worry about is making an HTTP connection to our API.</p>
<p>At the same time, we want the remote dbt MCP server to have similar functionality as the local dbt MCP server without entirely reimplementing the tools. We implemented these requirements by running a Streamable HTTP MCP server and adding proxied versions of each dbt MCP tool to this server. The proxied version of each tool has the same tool parameters, description, and implementation as the open source version, ensuring a consistent experience. The difference is that the proxied versions are configured via HTTP headers rather than environment variables and these tools connect directly to our internal APIs which reduces latency.</p>
<link href="/css/featherlight-styles.css" type="text/css" rel="stylesheet"><div class="
          docImage_EYbW
          
          
          
          
        "><span><a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/building-the-remote-dbt-mcp-server#" data-featherlight="/img/blog/2025-08-26-building-the-remote-dbt-mcp-server/remote-dbt-mcp.png"><img data-toggle="lightbox" alt="The remote dbt MCP architecture" title="The remote dbt MCP architecture" src="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/img/blog/2025-08-26-building-the-remote-dbt-mcp-server/remote-dbt-mcp.png?v=2"></a></span><span class="title_aGrV">The remote dbt MCP architecture</span></div>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="the-remote-dbt-mcp-server-in-action">The Remote dbt MCP Server in Action<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/building-the-remote-dbt-mcp-server#the-remote-dbt-mcp-server-in-action" class="hash-link" aria-label="Direct link to The Remote dbt MCP Server in Action" title="Direct link to The Remote dbt MCP Server in Action">​</a></h2>
<p>Now that we have a better understanding of how the remote dbt MCP server works, let's implement it in practice by creating a simple agent loop with LangGraph in Python. We are using LangGraph as an example here, but you can use whichever language or framework you would like. Check out our <a href="https://github.com/dbt-labs/dbt-mcp/tree/main/examples" target="_blank" rel="noopener noreferrer">examples directory</a> for more resources on creating agents with the dbt MCP server, including the full example shown here.</p>
<p>The agent we implement here will be able to conduct conversational analytics grounded in <strong>structured, governed context</strong> from your dbt project. This means it can receive a user's question, search for relevant metadata with the dbt Discovery API, find important metrics with dbt Semantic Layer API, explore the data, and return an accurate, trustworthy answer. This shows how the remote dbt MCP server can power AI applications that combine the flexibility of LLMs with the trust and consistency of your dbt assets.</p>
<p>For this example to work, you will need to install LangGraph dependencies and set an environment variable for the Anthropic API key:</p>
<div class="language-shell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#d6deeb;--prism-background-color:#011627"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-shell codeBlock_qGQc thin-scrollbar" style="color:#d6deeb;background-color:#011627"><code class="codeBlockLines_p187"><span class="token-line" style="color:#d6deeb"><span class="token plain">pip </span><span class="token function" style="color:rgb(130, 170, 255)">install</span><span class="token plain"> langgraph </span><span class="token string" style="color:rgb(173, 219, 103)">"langchain[anthropic]"</span><span class="token plain"> langchain-mcp-adapters</span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token builtin class-name" style="color:rgb(255, 203, 139)">export</span><span class="token plain"> </span><span class="token assign-left variable" style="color:rgb(214, 222, 235)">ANTHROPIC_API_KEY</span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token operator" style="color:rgb(127, 219, 202)">&lt;</span><span class="token plain">your-api-key</span><span class="token operator" style="color:rgb(127, 219, 202)">&gt;</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>First, we need to define the URL &amp; headers that the MCP client will use. These values will depend on your specific dbt Cloud deployment. In this example, we are setting the configuration from environment variables. For more information on this configuration, refer to <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/docs/dbt-ai/about-mcp">About dbt Model Context Protocol </a>.</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#d6deeb;--prism-background-color:#011627"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-python codeBlock_qGQc thin-scrollbar" style="color:#d6deeb;background-color:#011627"><code class="codeBlockLines_p187"><span class="token-line" style="color:#d6deeb"><span class="token keyword" style="color:rgb(127, 219, 202)">import</span><span class="token plain"> os</span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">url </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token string-interpolation string" style="color:rgb(173, 219, 103)">f"https://</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token string-interpolation interpolation">os</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token string-interpolation interpolation">environ</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token string-interpolation interpolation">get</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string-interpolation interpolation string" style="color:rgb(173, 219, 103)">'DBT_HOST'</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token string-interpolation string" style="color:rgb(173, 219, 103)">/api/ai/v1/mcp/"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">headers </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token string" style="color:rgb(173, 219, 103)">"x-dbt-user-id"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> os</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">environ</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">get</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(173, 219, 103)">"DBT_USER_ID"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token string" style="color:rgb(173, 219, 103)">"x-dbt-prod-environment-id"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> os</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">environ</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">get</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(173, 219, 103)">"DBT_PROD_ENV_ID"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token string" style="color:rgb(173, 219, 103)">"x-dbt-dev-environment-id"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> os</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">environ</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">get</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(173, 219, 103)">"DBT_DEV_ENV_ID"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token string" style="color:rgb(173, 219, 103)">"Authorization"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token string-interpolation string" style="color:rgb(173, 219, 103)">f"token </span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token string-interpolation interpolation">os</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token string-interpolation interpolation">environ</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token string-interpolation interpolation">get</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string-interpolation interpolation string" style="color:rgb(173, 219, 103)">'DBT_TOKEN'</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token string-interpolation string" style="color:rgb(173, 219, 103)">"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Next, we need to create an MCP client, so our agent knows how to use the remote dbt MCP server.</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#d6deeb;--prism-background-color:#011627"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-python codeBlock_qGQc thin-scrollbar" style="color:#d6deeb;background-color:#011627"><code class="codeBlockLines_p187"><span class="token-line" style="color:#d6deeb"><span class="token keyword" style="color:rgb(127, 219, 202)">from</span><span class="token plain"> langchain_mcp_adapters</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">client </span><span class="token keyword" style="color:rgb(127, 219, 202)">import</span><span class="token plain"> MultiServerMCPClient</span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">client </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> MultiServerMCPClient</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token string" style="color:rgb(173, 219, 103)">"dbt"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">      </span><span class="token string" style="color:rgb(173, 219, 103)">"url"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> url</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">      </span><span class="token string" style="color:rgb(173, 219, 103)">"headers"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> headers</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">      </span><span class="token string" style="color:rgb(173, 219, 103)">"transport"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"streamable_http"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Then, we need to get the available tools from the remote dbt MCP server.</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#d6deeb;--prism-background-color:#011627"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-python codeBlock_qGQc thin-scrollbar" style="color:#d6deeb;background-color:#011627"><code class="codeBlockLines_p187"><span class="token-line" style="color:#d6deeb"><span class="token plain">tools </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">await</span><span class="token plain"> client</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">get_tools</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Now, we can create our LangGraph agent.</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#d6deeb;--prism-background-color:#011627"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-python codeBlock_qGQc thin-scrollbar" style="color:#d6deeb;background-color:#011627"><code class="codeBlockLines_p187"><span class="token-line" style="color:#d6deeb"><span class="token keyword" style="color:rgb(127, 219, 202)">from</span><span class="token plain"> langgraph</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">prebuilt </span><span class="token keyword" style="color:rgb(127, 219, 202)">import</span><span class="token plain"> create_react_agent</span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">from</span><span class="token plain"> langgraph</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">checkpoint</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">memory </span><span class="token keyword" style="color:rgb(127, 219, 202)">import</span><span class="token plain"> InMemorySaver</span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">agent </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> create_react_agent</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">  model</span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token string" style="color:rgb(173, 219, 103)">"anthropic:claude-3-7-sonnet-latest"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">  tools</span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain">tools</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># This allows the agent to have conversational memory.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">  checkpointer</span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain">InMemorySaver</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Finally, we can run the agent in a loop. This example relies on <code>print_stream_item</code> which you can find in the full example <a href="https://github.com/dbt-labs/dbt-mcp/blob/365bc0f4c28b48510d194201370a5500d69cc5ea/examples/langgraph_agent/main.py#L11" target="_blank" rel="noopener noreferrer">here</a>. You can exit the loop by killing the program with CTRL+C.</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#d6deeb;--prism-background-color:#011627"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-python codeBlock_qGQc thin-scrollbar" style="color:#d6deeb;background-color:#011627"><code class="codeBlockLines_p187"><span class="token-line" style="color:#d6deeb"><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># This config maintains the conversation thread.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">config </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token string" style="color:rgb(173, 219, 103)">"configurable"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token string" style="color:rgb(173, 219, 103)">"thread_id"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"1"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">while</span><span class="token plain"> </span><span class="token boolean" style="color:rgb(255, 88, 116)">True</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">  user_input </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">input</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(173, 219, 103)">"User &gt; "</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">  agent_response </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> agent</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">invoke</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token string" style="color:rgb(173, 219, 103)">"messages"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token string" style="color:rgb(173, 219, 103)">"role"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"user"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"content"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> user_input</span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">    config</span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">  print_stream_item</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">item</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>With our agent implemented, we can run the program and ask it a question. You should see an output like this:</p>
<div class="language-shell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#d6deeb;--prism-background-color:#011627"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-shell codeBlock_qGQc thin-scrollbar" style="color:#d6deeb;background-color:#011627"><code class="codeBlockLines_p187"><span class="token-line" style="color:#d6deeb"><span class="token plain">User </span><span class="token operator" style="color:rgb(127, 219, 202)">&gt;</span><span class="token plain"> How much revenue did we </span><span class="token function" style="color:rgb(130, 170, 255)">make</span><span class="token plain"> last month?</span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">Agent </span><span class="token operator" style="color:rgb(127, 219, 202)">&gt;</span><span class="token plain"> I</span><span class="token string" style="color:rgb(173, 219, 103)">'ll help you find out the revenue for last month. Let me first check what metrics are available in the dbt Semantic Layer.</span><br></span><span class="token-line" style="color:#d6deeb"><span class="token string" style="color:rgb(173, 219, 103)">    using tool: list_metrics</span><br></span><span class="token-line" style="color:#d6deeb"><span class="token string" style="color:rgb(173, 219, 103)">Agent &gt; I see that we have a "revenue" metric available. Let me get the dimensions for this metric to understand how I can query for last month'</span><span class="token plain">s data:</span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">    using tool: get_dimensions</span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">Agent </span><span class="token operator" style="color:rgb(127, 219, 202)">&gt;</span><span class="token plain"> Now I</span><span class="token string" style="color:rgb(173, 219, 103)">'ll query the revenue metric for last month. I'</span><span class="token plain">ll use the </span><span class="token string" style="color:rgb(173, 219, 103)">"metric_time"</span><span class="token plain"> dimension with a MONTH grain:</span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">    using tool: query_metrics</span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">Agent </span><span class="token operator" style="color:rgb(127, 219, 202)">&gt;</span><span class="token plain"> Based on the results, the total revenue </span><span class="token keyword" style="color:rgb(127, 219, 202)">for</span><span class="token plain"> last month was **</span><span class="token variable" style="color:rgb(214, 222, 235)">$102</span><span class="token plain">,379.00**.</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="future-work">Future Work<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/building-the-remote-dbt-mcp-server#future-work" class="hash-link" aria-label="Direct link to Future Work" title="Direct link to Future Work">​</a></h2>
<p>Now that remote dbt MCP is available in public beta, we encourage you to build agents to interact with your dbt resources, bringing <strong>structured, governed context</strong> into AI workflows without the overhead of local setup. Here are some ideas for types of agents you can build with the remote dbt MCP server:</p>
<ul>
<li>Answer business-related questions with accurate, governed metrics from dbt</li>
<li>Identify PII columns and enforcing governance policies automatically</li>
<li>PR review agent to improve code quality and expedite the review process</li>
<li>Explore metadata and catalog information to accelerate data discovery and troubleshooting</li>
<li>On-call incident support agent to remediate issues faster</li>
</ul>
<p>We are continuing to invest in remote dbt MCP, with upcoming features like OAuth-based authentication to make remote MCP authentication &amp; authorization even easier. If you have any feedback, need help, or just want to chat, join us in the #tools-dbt-mcp channel in <a href="https://www.getdbt.com/community/join-the-community" target="_blank" rel="noopener noreferrer">our community Slack</a>.</p>]]></content>
        <author>
            <name>Devon Fulcher</name>
        </author>
        <category label="ai" term="ai"/>
        <category label="data ecosystem" term="data ecosystem"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[How to train a linear regression model with dbt and BigFrames]]></title>
        <id>https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/train-linear-dbt-bigframes</id>
        <link href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/train-linear-dbt-bigframes"/>
        <updated>2025-07-11T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[How to build a scalable linear regression model by combining dbt's modular orchestration with BigFrames' in-database Python execution in BigQuery.]]></summary>
        <content type="html"><![CDATA[<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="introduction-to-dbt-and-bigframes">Introduction to dbt and BigFrames<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/train-linear-dbt-bigframes#introduction-to-dbt-and-bigframes" class="hash-link" aria-label="Direct link to Introduction to dbt and BigFrames" title="Direct link to Introduction to dbt and BigFrames">​</a></h2>
<p><strong>dbt</strong>: A framework for transforming data in modern data warehouses using modular SQL or Python. dbt enables data teams to develop analytics code collaboratively and efficiently by applying software engineering best practices such as version control, modularity, portability, CI/CD, testing, and documentation. For more information, refer to <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/docs/introduction#dbt">What is dbt?</a></p>
<p><strong>BigQuery DataFrames (BigFrames)</strong>: An open-source Python library offered by Google. BigFrames scales Python data processing by transpiling common Python data science APIs (pandas and scikit-learn) to BigQuery SQL.</p>
<p>You can read more in the <a href="https://cloud.google.com/bigquery/docs/bigquery-dataframes-introduction" target="_blank" rel="noopener noreferrer">official BigFrames guide</a> and view the <a href="https://github.com/googleapis/python-bigquery-dataframes" target="_blank" rel="noopener noreferrer">public BigFrames GitHub repository</a>.</p>
<p>By combining dbt with BigFrames via the <code>dbt-bigquery</code> adapter (referred to as <em>"dbt-BigFrames"</em>), you gain:</p>
<ul>
<li>dbt’s modular SQL and Python modeling, dependency management with dbt.ref(), environment configurations, and data testing. With the cloud-based dbt platform, you also get job scheduling and monitoring.</li>
<li>BigFrames’ ability to execute complex Python transformations (including machine learning) directly in BigQuery.</li>
</ul>
<p><code>dbt-BigFrames</code> utilizes the <strong>Colab Enterprise notebook executor service</strong> in a GCP project to run Python models. These notebooks execute BigFrames code, which is translated into BigQuery SQL.</p>
<blockquote>
<p>Refer to these guides to learn more: <a href="https://cloud.google.com/bigquery/docs/dataframes-dbt" target="_blank" rel="noopener noreferrer">Use BigQuery DataFrames in dbt</a> or <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/guides/dbt-python-bigframes?step=1">Using BigQuery DataFrames with dbt Python models</a>.</p>
</blockquote>
<p>To illustrate the practical impact of combining dbt with BigFrames, the following sections explore how this integration can streamline and scale a common machine learning task: training a linear regression model on large datasets.</p>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="the-power-of-dbt-bigframes-for-large-scale-linear-regression">The power of dbt-BigFrames for large-scale linear regression<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/train-linear-dbt-bigframes#the-power-of-dbt-bigframes-for-large-scale-linear-regression" class="hash-link" aria-label="Direct link to The power of dbt-BigFrames for large-scale linear regression" title="Direct link to The power of dbt-BigFrames for large-scale linear regression">​</a></h2>
<p>Linear regression is a cornerstone of predictive analytics, used in:</p>
<ul>
<li>Sales forecasting</li>
<li>Financial modeling</li>
<li>Demand planning</li>
<li>Real estate valuation</li>
</ul>
<p>These tasks often require processing datasets too large for traditional in-memory Python. BigFrames alone solves this, but combining it with dbt offers a structured, maintainable, and production-ready way to train models or generate batch predictions on large data.</p>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="dbt-bigframes-with-ml-a-practical-example">“dbt-BigFrames” with ML: A practical example<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/train-linear-dbt-bigframes#dbt-bigframes-with-ml-a-practical-example" class="hash-link" aria-label="Direct link to “dbt-BigFrames” with ML: A practical example" title="Direct link to “dbt-BigFrames” with ML: A practical example">​</a></h2>
<p>We’ll walk through training a linear regression model using a <strong>dbt Python model powered by BigFrames</strong>, focusing on the structure and orchestration provided by dbt.</p>
<p>We’ll use the <code>epa_historical_air_quality</code> dataset from BigQuery Public Data (courtesy of the U.S. Environmental Protection Agency).</p>
<h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="problem-statement">Problem statement<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/train-linear-dbt-bigframes#problem-statement" class="hash-link" aria-label="Direct link to Problem statement" title="Direct link to Problem statement">​</a></h3>
<p>Develop a machine learning model to predict atmospheric ozone levels using historical air quality and environmental sensor data, enabling more accurate monitoring and forecasting of air pollution trends.</p>
<p><strong>Key stages:</strong></p>
<ol>
<li><strong>Data Foundation</strong>: Transform raw source tables into an analysis-ready dataset.</li>
<li><strong>Machine learning Analysis</strong>: Train a linear regression model on the cleaned data.</li>
</ol>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="setting-up-your-dbt-project-for-bigframes">Setting up your dbt project for BigFrames<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/train-linear-dbt-bigframes#setting-up-your-dbt-project-for-bigframes" class="hash-link" aria-label="Direct link to Setting up your dbt project for BigFrames" title="Direct link to Setting up your dbt project for BigFrames">​</a></h2>
<h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="prerequisites">Prerequisites<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/train-linear-dbt-bigframes#prerequisites" class="hash-link" aria-label="Direct link to Prerequisites" title="Direct link to Prerequisites">​</a></h3>
<ul>
<li>A Google Cloud account</li>
<li>A dbt platform or Core setup</li>
<li>Basic to intermediate SQL and Python</li>
<li>Familiarity with dbt using <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/guides?level=Beginner">Beginner dbt guides</a></li>
</ul>
<h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="sample-profilesyml-for-bigframes">Sample <code>profiles.yml</code> for BigFrames<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/train-linear-dbt-bigframes#sample-profilesyml-for-bigframes" class="hash-link" aria-label="Direct link to sample-profilesyml-for-bigframes" title="Direct link to sample-profilesyml-for-bigframes">​</a></h3>
<div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#d6deeb;--prism-background-color:#011627"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-yaml codeBlock_qGQc thin-scrollbar" style="color:#d6deeb;background-color:#011627"><code class="codeBlockLines_p187"><span class="token-line" style="color:#d6deeb"><span class="token key atrule" style="color:rgb(255, 203, 139)">my_epa_project</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token key atrule" style="color:rgb(255, 203, 139)">outputs</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token key atrule" style="color:rgb(255, 203, 139)">dev</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">      </span><span class="token key atrule" style="color:rgb(255, 203, 139)">compute_region</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> us</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">central1</span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">      </span><span class="token key atrule" style="color:rgb(255, 203, 139)">dataset</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> your_bq_dataset</span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">      </span><span class="token key atrule" style="color:rgb(255, 203, 139)">gcs_bucket</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> your_gcs_bucket</span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">      </span><span class="token key atrule" style="color:rgb(255, 203, 139)">location</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> US</span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">      </span><span class="token key atrule" style="color:rgb(255, 203, 139)">method</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> oauth</span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">      </span><span class="token key atrule" style="color:rgb(255, 203, 139)">priority</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> interactive</span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">      </span><span class="token key atrule" style="color:rgb(255, 203, 139)">project</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> your_gcp_project</span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">      </span><span class="token key atrule" style="color:rgb(255, 203, 139)">threads</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">1</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">      </span><span class="token key atrule" style="color:rgb(255, 203, 139)">type</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> bigquery</span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token key atrule" style="color:rgb(255, 203, 139)">target</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> dev</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="sample-dbt_projectyml">Sample <code>dbt_project.yml</code><a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/train-linear-dbt-bigframes#sample-dbt_projectyml" class="hash-link" aria-label="Direct link to sample-dbt_projectyml" title="Direct link to sample-dbt_projectyml">​</a></h3>
<div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#d6deeb;--prism-background-color:#011627"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-yaml codeBlock_qGQc thin-scrollbar" style="color:#d6deeb;background-color:#011627"><code class="codeBlockLines_p187"><span class="token-line" style="color:#d6deeb"><span class="token key atrule" style="color:rgb(255, 203, 139)">name</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">'my_epa_project'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token key atrule" style="color:rgb(255, 203, 139)">version</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">'1.0.0'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token key atrule" style="color:rgb(255, 203, 139)">config-version</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">2</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token key atrule" style="color:rgb(255, 203, 139)">models</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">  </span><span class="token key atrule" style="color:rgb(255, 203, 139)">my_epa_project</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token key atrule" style="color:rgb(255, 203, 139)">submission_method</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> bigframes</span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token key atrule" style="color:rgb(255, 203, 139)">notebook_template_id</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> 701881164074529xxxx  </span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># Optional</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token key atrule" style="color:rgb(255, 203, 139)">timeout</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">6000</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token key atrule" style="color:rgb(255, 203, 139)">example</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">      </span><span class="token key atrule" style="color:rgb(255, 203, 139)">+materialized</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> view</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="the-dbt-python-models-for-linear-regression">The dbt Python models for linear regression<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/train-linear-dbt-bigframes#the-dbt-python-models-for-linear-regression" class="hash-link" aria-label="Direct link to The dbt Python models for linear regression" title="Direct link to The dbt Python models for linear regression">​</a></h2>
<p>This project uses <strong>two modular dbt Python models</strong>:</p>
<ol>
<li><code>prepare_table.py</code> — Ingests and prepares data</li>
<li><code>prediction.py</code> — Trains the model and generates predictions</li>
</ol>
<h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="part-1-preparing-the-table-prepare_tablepy">Part 1: Preparing the table (<code>prepare_table.py</code>)<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/train-linear-dbt-bigframes#part-1-preparing-the-table-prepare_tablepy" class="hash-link" aria-label="Direct link to part-1-preparing-the-table-prepare_tablepy" title="Direct link to part-1-preparing-the-table-prepare_tablepy">​</a></h3>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#d6deeb;--prism-background-color:#011627"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-python codeBlock_qGQc thin-scrollbar" style="color:#d6deeb;background-color:#011627"><code class="codeBlockLines_p187"><span class="token-line" style="color:#d6deeb"><span class="token keyword" style="color:rgb(127, 219, 202)">def</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">model</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">dbt</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> session</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">    dbt</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">config</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">submission_method</span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token string" style="color:rgb(173, 219, 103)">"bigframes"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> timeout</span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token number" style="color:rgb(247, 140, 108)">6000</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">    dataset </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"bigquery-public-data.epa_historical_air_quality"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">    index_columns </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token string" style="color:rgb(173, 219, 103)">"state_name"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"county_name"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"site_num"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"date_local"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"time_local"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">    param_column </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"parameter_name"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">    value_column </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"sample_measurement"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">    params_dfs </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">    table_param_dict </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">        </span><span class="token string" style="color:rgb(173, 219, 103)">"co_hourly_summary"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"co"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">        </span><span class="token string" style="color:rgb(173, 219, 103)">"no2_hourly_summary"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"no2"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">        </span><span class="token string" style="color:rgb(173, 219, 103)">"o3_hourly_summary"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"o3"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">        </span><span class="token string" style="color:rgb(173, 219, 103)">"pressure_hourly_summary"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"pressure"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">        </span><span class="token string" style="color:rgb(173, 219, 103)">"so2_hourly_summary"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"so2"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">        </span><span class="token string" style="color:rgb(173, 219, 103)">"temperature_hourly_summary"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"temperature"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token keyword" style="color:rgb(127, 219, 202)">for</span><span class="token plain"> table</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> param </span><span class="token keyword" style="color:rgb(127, 219, 202)">in</span><span class="token plain"> table_param_dict</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">items</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">        param_df </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> bpd</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">read_gbq</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string-interpolation string" style="color:rgb(173, 219, 103)">f"</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token string-interpolation interpolation">dataset</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token string-interpolation string" style="color:rgb(173, 219, 103)">.</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token string-interpolation interpolation">table</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token string-interpolation string" style="color:rgb(173, 219, 103)">"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> columns</span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain">index_columns </span><span class="token operator" style="color:rgb(127, 219, 202)">+</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token plain">value_column</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">        param_df </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> param_df</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">sort_values</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">index_columns</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">drop_duplicates</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">index_columns</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">set_index</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">index_columns</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">rename</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">columns</span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain">value_column</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> param</span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">        params_dfs</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">append</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">param_df</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">    wind_table </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token string-interpolation string" style="color:rgb(173, 219, 103)">f"</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token string-interpolation interpolation">dataset</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token string-interpolation string" style="color:rgb(173, 219, 103)">.wind_hourly_summary"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">    wind_speed_df </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> bpd</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">read_gbq</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">        wind_table</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">        columns</span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain">index_columns </span><span class="token operator" style="color:rgb(127, 219, 202)">+</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token plain">value_column</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">        filters</span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">param_column</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"=="</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"Wind Speed - Resultant"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">    wind_speed_df </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> wind_speed_df</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">sort_values</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">index_columns</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">drop_duplicates</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">index_columns</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">set_index</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">index_columns</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">rename</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">columns</span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain">value_column</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"wind_speed"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">    params_dfs</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">append</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">wind_speed_df</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">    df </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> bpd</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">concat</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">params_dfs</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> axis</span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token number" style="color:rgb(247, 140, 108)">1</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> join</span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token string" style="color:rgb(173, 219, 103)">"inner"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">cache</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token keyword" style="color:rgb(127, 219, 202)">return</span><span class="token plain"> df</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">reset_index</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="part-2-training-the-model-and-making-predictions-predictionpy">Part 2: Training the model and making predictions (<code>prediction.py</code>)<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/train-linear-dbt-bigframes#part-2-training-the-model-and-making-predictions-predictionpy" class="hash-link" aria-label="Direct link to part-2-training-the-model-and-making-predictions-predictionpy" title="Direct link to part-2-training-the-model-and-making-predictions-predictionpy">​</a></h3>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#d6deeb;--prism-background-color:#011627"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-python codeBlock_qGQc thin-scrollbar" style="color:#d6deeb;background-color:#011627"><code class="codeBlockLines_p187"><span class="token-line" style="color:#d6deeb"><span class="token keyword" style="color:rgb(127, 219, 202)">def</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">model</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">dbt</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> session</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">    dbt</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">config</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">submission_method</span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token string" style="color:rgb(173, 219, 103)">"bigframes"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> timeout</span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token number" style="color:rgb(247, 140, 108)">6000</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">    df </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> dbt</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">ref</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(173, 219, 103)">"prepare_table"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">    train_data_filter </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">df</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">date_local</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">dt</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">year </span><span class="token operator" style="color:rgb(127, 219, 202)">&lt;</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">2017</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">    test_data_filter </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">df</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">date_local</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">dt</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">year </span><span class="token operator" style="color:rgb(127, 219, 202)">&gt;=</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">2017</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(127, 219, 202)">&amp;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">df</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">date_local</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">dt</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">year </span><span class="token operator" style="color:rgb(127, 219, 202)">&lt;</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">2020</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">    predict_data_filter </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">df</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">date_local</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">dt</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">year </span><span class="token operator" style="color:rgb(127, 219, 202)">&gt;=</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">2020</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">    index_columns </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token string" style="color:rgb(173, 219, 103)">"state_name"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"county_name"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"site_num"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"date_local"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"time_local"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">    df_train </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> df</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token plain">train_data_filter</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">set_index</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">index_columns</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">    df_test </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> df</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token plain">test_data_filter</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">set_index</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">index_columns</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">    df_predict </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> df</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token plain">predict_data_filter</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">set_index</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">index_columns</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">    X_train</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> y_train </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> df_train</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">drop</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">columns</span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token string" style="color:rgb(173, 219, 103)">"o3"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> df_train</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token string" style="color:rgb(173, 219, 103)">"o3"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">    X_test</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> y_test </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> df_test</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">drop</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">columns</span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token string" style="color:rgb(173, 219, 103)">"o3"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> df_test</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token string" style="color:rgb(173, 219, 103)">"o3"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">    X_predict </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> df_predict</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">drop</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">columns</span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token string" style="color:rgb(173, 219, 103)">"o3"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token keyword" style="color:rgb(127, 219, 202)">from</span><span class="token plain"> bigframes</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">ml</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">linear_model </span><span class="token keyword" style="color:rgb(127, 219, 202)">import</span><span class="token plain"> LinearRegression</span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">    model </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> LinearRegression</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">    model</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">fit</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">X_train</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> y_train</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">    df_pred </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> model</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">predict</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">X_predict</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token keyword" style="color:rgb(127, 219, 202)">return</span><span class="token plain"> df_pred</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="running-your-dbt-ml-pipeline">Running your dbt ML pipeline<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/train-linear-dbt-bigframes#running-your-dbt-ml-pipeline" class="hash-link" aria-label="Direct link to Running your dbt ML pipeline" title="Direct link to Running your dbt ML pipeline">​</a></h2>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#d6deeb;--prism-background-color:#011627"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-bash codeBlock_qGQc thin-scrollbar" style="color:#d6deeb;background-color:#011627"><code class="codeBlockLines_p187"><span class="token-line" style="color:#d6deeb"><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># Run all models</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">dbt run</span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic"># Or run just your new models</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">dbt run </span><span class="token parameter variable" style="color:rgb(214, 222, 235)">--select</span><span class="token plain"> prepare_table prediction</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="key-advantages-of-dbt-and-bigframes-for-ml">Key advantages of dbt and BigFrames for ML<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/train-linear-dbt-bigframes#key-advantages-of-dbt-and-bigframes-for-ml" class="hash-link" aria-label="Direct link to Key advantages of dbt and BigFrames for ML" title="Direct link to Key advantages of dbt and BigFrames for ML">​</a></h2>
<ul>
<li><strong>Scalability &amp; Efficiency</strong>: Handle large datasets in BigQuery via BigFrames</li>
<li><strong>Simplified Workflow</strong>: Use familiar APIs like <code>pandas</code> and <code>scikit-learn</code></li>
<li><strong>dbt Orchestration</strong>:<!-- -->
<ul>
<li>Dependency management with <code>dbt.ref()</code> and <code>dbt.source()</code></li>
<li>Scheduled retraining with <code>dbt run</code></li>
<li>Testing, documentation, and reproducibility</li>
</ul>
</li>
</ul>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="conclusion-and-next-steps">Conclusion and next steps<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/train-linear-dbt-bigframes#conclusion-and-next-steps" class="hash-link" aria-label="Direct link to Conclusion and next steps" title="Direct link to Conclusion and next steps">​</a></h2>
<p>By integrating <strong>BigFrames</strong> into your <strong>dbt workflows</strong>, you can build scalable, maintainable, and production-ready machine learning pipelines. While this example used linear regression, the same principles apply across other ML use cases with <code>bigframes.ml</code>.</p>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="feedback-and-support">Feedback and support<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/train-linear-dbt-bigframes#feedback-and-support" class="hash-link" aria-label="Direct link to Feedback and support" title="Direct link to Feedback and support">​</a></h2>
<ul>
<li>📚 <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/docs/dbt-support">dbt Support</a></li>
<li>📨 Email feedback on BigFrames: <a href="mailto:bigframes-feedback@google.com" target="_blank" rel="noopener noreferrer">bigframes-feedback@google.com</a></li>
<li>🛠 <a href="https://github.com/googleapis/python-bigquery-dataframes" target="_blank" rel="noopener noreferrer">File issues on GitHub</a></li>
<li>📬 <a href="https://docs.google.com/forms/d/10EnDyYdYUW9HvelHYuBRC8L3GdGVl3rX0aroinbRZyc/viewform?edit_requested=true" target="_blank" rel="noopener noreferrer">Subscribe to BigFrames updates</a></li>
</ul>]]></content>
        <author>
            <name>Jialuo Chen</name>
        </author>
        <category label="analytics craft" term="analytics craft"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[The new dbt VS Code extension: The experience we've all been waiting for]]></title>
        <id>https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/vscode-extension-experience</id>
        <link href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/vscode-extension-experience"/>
        <updated>2025-06-25T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[How the new dbt VS Code extension finally delivers the dev experience we've always wanted.]]></summary>
        <content type="html"><![CDATA[<p>Hello, community!</p>
<p>My name is Bruno, and you might have seen me posting dbt content on LinkedIn. If you haven't, let me introduce myself. I started working with dbt more than 3 years ago. At that time, I was very new to the tool, and to understand it a bit better, I started creating some resources to help me with dbt learning. One of them, a dbt cheatsheet, was the starting point for my community journey.</p>
<p>I went from this cheatsheet to creating all different kinds of content, contributing and engaging with the community, until I got the dbt community award two times, and I am very thankful and proud about that.</p>
<p>Since the acquisition of SDF Labs by dbt Labs, I have been waiting for the day that we would see what the result of the fusion of these two companies would be. Spoiler alert: It’s the dbt Fusion engine and it's better than I could have expected.</p>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="the-dbt-developer-experience-in-the-pre-fusion-era">The dbt developer experience in the pre-fusion-era<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/vscode-extension-experience#the-dbt-developer-experience-in-the-pre-fusion-era" class="hash-link" aria-label="Direct link to The dbt developer experience in the pre-fusion-era" title="Direct link to The dbt developer experience in the pre-fusion-era">​</a></h2>
<p>If you've ever started a dbt project, chances are your journey began like mine did: cloning <code>jaffle_shop</code>, opening it in VS Code, and running <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/reference/commands/run"><code>dbt run</code></a> for the first time (actually the second time, because I know you forgot to run <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/reference/commands/deps"><code>dbt deps</code></a> in the first one). This is the dbt initiation process, our ‘hello-world’.</p>
<p>You played around with <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/best-practices/how-we-structure/2-staging#staging-models">staging models</a>, the orders table, customers table. But let's be honest, the developer experience in that setup was always a bit... clunky.</p>
<p>You wanted to check the lineage of your project, one of the coolest features of dbt, and you had to run <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/reference/commands/cmd-docs#dbt-docs-generate"><code>dbt docs generate</code></a>, <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/reference/commands/cmd-docs#dbt-docs-serve"><code>serve</code></a>, and open the docs in a browser. Made some updates? Do all the steps again.</p>
<p>Did you want to check your project's metadata? You had to rely on <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/reference/commands/cmd-docs"><code>dbt docs</code></a> (that whole process again), or build some custom solution with the <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/reference/artifacts/manifest-json"><code>manifest.json</code></a>.</p>
<p>Moving to dbt Cloud (now called just <span>dbt platform</span>) made things smoother. It has a built-in <span>Studio IDE</span> with git integration, easier to compile and preview models. An auto-updating lineage tab below the model, a much better documentation with dbt Explorer, now renamed to Catalog. And a lot of other powerful features for orchestration, observability, CI/CD, and more.</p>
<p>The cloud-based <span>dbt platform</span> was a big step up, but even so, many of us still preferred to use our own dev environments. We like using our themes, our VS Code extensions, our terminals, but this would mean losing all the nice cloud features while developing. A sad trade-off.</p>
<p>We've already been to <span>dbt platform</span> platform and back to the terminal, and some problems remain. Consider this all too common scenario when modifying a dbt model: forgetting a comma[1]. You don't learn your mistake until after dbt tries to run this model on your warehouse, but dbt can't do this until your cluster is turned on. So it's not until a full minute later that you get the feedback about your missing punctuation mark.</p>
<p>[1]: because you are using trailing commas instead of leading commas, and they're harder to see, and I'm talking too much about the comma fight.</p>
<p>All this back-and-forth communication of dbt and the platform was slowing down your project.</p>
<p>That’s why this new release is such a big deal. It solves all the problems above and introduces other things I didn't know I needed until I saw it.</p>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="the-new-era-of-dbt-development">The new era of dbt development<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/vscode-extension-experience#the-new-era-of-dbt-development" class="hash-link" aria-label="Direct link to The new era of dbt development" title="Direct link to The new era of dbt development">​</a></h2>
<p>With the acquisition of SDF Labs and a renewed focus on developer experience, dbt Labs announced its new engine, <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/docs/fusion/about-fusion">Fusion</a>. This engine was built from zero with Rust, and its intelligence will power up dbt, no matter where you run it. There are different ways you can use the Fusion engine, and the best one is with the also announced VS Code extension.</p>
<p>The Fusion engine with the VS Code extension is how folks will want to develop with dbt moving forward. I can say this feels like the experience we’ve all been waiting for.</p>
<p>After using it, it’s hard to imagine going back. Working with dbt in VS Code without this extension just doesn’t make sense anymore.</p>
<p>It comes with a lot of features to streamline your work and make you more efficient by developing faster and spending less. But let me tell you about my favorites:</p>
<h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="catch-sql-errors-in-real-time">Catch SQL Errors in Real Time<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/vscode-extension-experience#catch-sql-errors-in-real-time" class="hash-link" aria-label="Direct link to Catch SQL Errors in Real Time" title="Direct link to Catch SQL Errors in Real Time">​</a></h3>
<p>There was no question what I was picking first. No more waiting for your platform to debug your code for you. If you misspell a column name or goof up a function's order of parameters, you catch those errors before you run anything.</p>
<p>This is because Fusion doesn't treat SQL code as just a string anymore; it really understands it. It also shows you some helpful information about the error.</p>
<link href="/css/featherlight-styles.css" type="text/css" rel="stylesheet"><div class="
          docImage_EYbW
          
          
          
          
        "><span><a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/vscode-extension-experience#" data-featherlight="/img/blog/2025-06-16-the-new-dbt-vscode-extension/vs_code_extension_function_error.png"><img data-toggle="lightbox" alt="Showing function errors." title="Showing function errors." src="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/img/blog/2025-06-16-the-new-dbt-vscode-extension/vs_code_extension_function_error.png?v=2"></a></span><span class="title_aGrV">Showing function errors.</span></div>
<link href="/css/featherlight-styles.css" type="text/css" rel="stylesheet"><div class="
          docImage_EYbW
          
          
          
          
        "><span><a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/vscode-extension-experience#" data-featherlight="/img/blog/2025-06-16-the-new-dbt-vscode-extension/vs_code_extension_column_error.png"><img data-toggle="lightbox" alt="Showing column name errors." title="Showing column name errors." src="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/img/blog/2025-06-16-the-new-dbt-vscode-extension/vs_code_extension_column_error.png?v=2"></a></span><span class="title_aGrV">Showing column name errors.</span></div>
<p>This is the greatest improvement of this engine, IMHO.</p>
<h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="model-and-column-lineage">Model and Column Lineage<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/vscode-extension-experience#model-and-column-lineage" class="hash-link" aria-label="Direct link to Model and Column Lineage" title="Direct link to Model and Column Lineage">​</a></h3>
<p>My next favorite feature is the lineage view. If you were a <span>dbt</span> platform user, you would feel at home. And if you were using dbt Core, finally, no more generating <code>dbt docs</code> to visualize lineage.</p>
<p>Now there's a tab lineage tab that shows your project’s lineage directly in VS Code. It’s interactive and live. You can use the lenses feature, that's pretty cool to have a good visualization of your project by different attributes like resource_type, or materialization.</p>
<link href="/css/featherlight-styles.css" type="text/css" rel="stylesheet"><div class="
          docImage_EYbW
          
          
          
          
        "><span><a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/vscode-extension-experience#" data-featherlight="/img/blog/2025-06-16-the-new-dbt-vscode-extension/vs_code_extension_project_lineage.png"><img data-toggle="lightbox" alt="Project Lineage." title="Project Lineage." src="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/img/blog/2025-06-16-the-new-dbt-vscode-extension/vs_code_extension_project_lineage.png?v=2"></a></span><span class="title_aGrV">Project Lineage.</span></div>
<p>And something I was not expecting to be here, but thankfully it is, column-level lineage! Not just where columns come from, but also how they change: renamed, transformed, or passed through.</p>
<p>This is incredibly helpful for debugging transformations or understanding how that key metric is shaped across models.</p>
<link href="/css/featherlight-styles.css" type="text/css" rel="stylesheet"><div class="
          docImage_EYbW
          
          
          
          
        "><span><a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/vscode-extension-experience#" data-featherlight="/img/blog/2025-06-16-the-new-dbt-vscode-extension/vs_code_extension_cll.png"><img data-toggle="lightbox" alt="Column-level Lineage." title="Column-level Lineage." src="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/img/blog/2025-06-16-the-new-dbt-vscode-extension/vs_code_extension_cll.png?v=2"></a></span><span class="title_aGrV">Column-level Lineage.</span></div>
<h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="instant-refactoring">Instant refactoring<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/vscode-extension-experience#instant-refactoring" class="hash-link" aria-label="Direct link to Instant refactoring" title="Direct link to Instant refactoring">​</a></h3>
<p>Ok, let me show you just one more thing! Have you ever faced a situation where you'd like to rename a model or a column, but it's used many places downstream that you give up because you don't want to refactor everything or you are afraid you will break something?</p>
<p>Now, thanks to the deep dbt Fusion SQL understanding, you can rename your model or column, and the extension will refactor all downstream dependencies for you. But don't worry, before doing it, the extension allows you to see a preview of the changes, so you can be sure it is doing what you want.</p>
<video width="100%" height="100%" muted="" controls=""><source src="/img/blog/2025-06-16-the-new-dbt-vscode-extension/vs_code_extension_refactoring.webm" type="video/webm"></video>
<p>There are a lot more other features this extension is bringing, like navigating through models instantly, autocompleting everything, renaming models or columns and being warned how it will impact your project, previewing models &amp; CTEs, and other features that are already covered in other blogs. By the way, it just launched, so I believe we can expect more and more enhancements to come.</p>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="conclusion-a-new-default">Conclusion: A New Default<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/vscode-extension-experience#conclusion-a-new-default" class="hash-link" aria-label="Direct link to Conclusion: A New Default" title="Direct link to Conclusion: A New Default">​</a></h2>
<p>This extension changes what using dbt feels like. It brings together performance, context, and interactivity in a way that finally makes dbt feel at home inside a modern developer environment. And the best part? It’s just getting started.</p>
<p>The Fusion engine is already powering a faster, smarter dbt under the hood. And it opens the door to a more fluid, confident, and intuitive development experience. Fewer context switches. Fewer gotchas. More time spent thinking about your data, not your tooling.</p>
<p>If you’ve ever built models in a text editor and wished dbt “just knew more,” this is for you.</p>
<p>If you’ve relied on the CLI but missed having true autocomplete, this is for you.</p>
<p>And if you’ve wanted the best of both worlds, the flexibility of Core with the power of Cloud, this might just become your new default. Even if you use dbt Cloud, it powers up dbt-core to another level.</p>
<p>We’re incredibly excited to see how the community builds with this. Try it out. Push it. Share what’s working, and what’s missing.</p>
<p>This new extension will be constantly updated, so stay tuned for more improvements.</p>
<p><strong>This is the experience we’ve all been waiting for.</strong></p>
<p><em>Bruno is a lead Data Engineer at <a href="https://www.phdata.io/" target="_blank" rel="noopener noreferrer">phData</a>, and recently built a dbt learning platform called <a href="https://www.datagym.io/" target="_blank" rel="noopener noreferrer">DataGym.io</a>.</em></p>]]></content>
        <author>
            <name>Bruno Souza de Lima</name>
        </author>
        <category label="analytics craft" term="analytics craft"/>
        <category label="data ecosystem" term="data ecosystem"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[The Components of the dbt Fusion engine and how they fit together]]></title>
        <id>https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-fusion-engine-components</id>
        <link href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-fusion-engine-components"/>
        <updated>2025-05-28T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[The new engine makes it possible to decouple source code from functionality, introducing new ways to distribute functionality to the Community.]]></summary>
        <content type="html"><![CDATA[<p>Today, we announced the <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-fusion-engine">dbt Fusion engine</a>.</p>
<p>Fusion isn't just one thing — it's a set of interconnected components working together to power the next generation of analytics engineering.</p>
<p>This post maps out each piece of the Fusion architecture, explains how they fit together, and clarifies what's available to you whether you're compiling from source, using our pre-built binaries, or developing within a dbt Fusion powered product experience.</p>
<p>From the Rust engine to the VS Code extension, through to new Arrow-based adapters and Apache-licensed foundational technologies, we'll break down exactly what each component does, how each component is licensed (for why, see <a href="https://www.getdbt.com/blog/new-code-new-license-understanding-the-new-license-for-the-dbt-fusion-engine" target="_blank" rel="noopener noreferrer">Tristan's accompanying post</a>), and how you can start using it and get involved today.</p>
<p><em>This post describes the state of the world as it will be when Fusion reaches General Availability. For a look at the path to GA, read <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-fusion-engine-path-to-ga">this post</a>.</em></p>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="ways-to-access">There are a number of different ways to access the dbt Fusion engine<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-fusion-engine-components#ways-to-access" class="hash-link" aria-label="Direct link to There are a number of different ways to access the dbt Fusion engine" title="Direct link to There are a number of different ways to access the dbt Fusion engine">​</a></h2>
<p>A big change between the dbt Fusion engine and the dbt Core engine is their language. Core is Python; Fusion is Rust. This is meaningful not just because of the performance benefits, but because it creates a new way for us to distribute functionality to the community.</p>
<p>To distribute a Python program, you also have to distribute its underlying source code. But Rust is a compiled language, meaning we can share either the source code or just the compiled binaries derived from that source code.</p>
<p>This means that features which would have otherwise had to stay completely proprietary for IP reasons can instead be broadly distributed in binary form. There's also a completely source-available version of dbt Fusion which will exceed dbt Core's capabilities by the time we reach GA.</p>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="what-variants-of-the-dbt-fusion-engine-exist">What variants of the dbt Fusion engine exist?<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-fusion-engine-components#what-variants-of-the-dbt-fusion-engine-exist" class="hash-link" aria-label="Direct link to What variants of the dbt Fusion engine exist?" title="Direct link to What variants of the dbt Fusion engine exist?">​</a></h2>
<h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="source-available-dbt-fusion-engine">Source-available dbt Fusion engine<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-fusion-engine-components#source-available-dbt-fusion-engine" class="hash-link" aria-label="Direct link to Source-available dbt Fusion engine" title="Direct link to Source-available dbt Fusion engine">​</a></h3>
<p>Artifact type: Code</p>
<p>Available at: <a href="https://github.com/dbt-labs/dbt-fusion" target="_blank" rel="noopener noreferrer">https://github.com/dbt-labs/dbt-fusion</a> (Note: this repo currently only contains the code necessary for a <code>dbt parse</code> and <code>dbt deps</code> - more will follow!)</p>
<p>License: ELv2</p>
<p>This will be the foundation of the Fusion engine - the code that lets you:</p>
<ul>
<li>Execute your <code>dbt seed/run/test/build</code></li>
<li>Render your Jinja and create your DAG</li>
<li>Connect to the adapters that render your dbt project into the DDL and DML that hits your warehouse</li>
<li>Produce the artifacts in your dbt project</li>
</ul>
<p>To be clear, the self-compiled binary that's available today doesn't do much yet. By the time the new engine enters general availability, its source-available components will <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-fusion-engine-path-to-ga">exceed the net capabilities of dbt Core</a>. <strong>If you are a data team running dbt Core, simply running the self-compiled version of dbt Fusion will be a pure upgrade.</strong></p>
<p>This repository will also include the code necessary for <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/the-levels-of-sql-comprehension#level-1-parsing">Level 1 SQL Comprehension</a> (the ability to parse SQL into a syntax tree).</p>
<p>As long as you comply with the <a href="http://www.getdbt.com/licenses-faq" target="_blank" rel="noopener noreferrer">three restrictions in ELv2</a>:</p>
<ul>
<li>✅&nbsp;You can adopt the binary into your data workflows without dbt Labs' involvement</li>
<li>✅&nbsp;You&nbsp;can see and modify the code</li>
</ul>
<h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="precompiled-dbt-fusion-engine-binary">Precompiled dbt Fusion engine binary<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-fusion-engine-components#precompiled-dbt-fusion-engine-binary" class="hash-link" aria-label="Direct link to Precompiled dbt Fusion engine binary" title="Direct link to Precompiled dbt Fusion engine binary">​</a></h3>
<p>Artifact type: Precompiled binary</p>
<p>How to access: download following the instructions <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/docs/local/install-dbt?version=2">here</a></p>
<p>License: ELv2</p>
<p>When you download the precompiled binary created by dbt Labs, it contains:</p>
<ul>
<li>
<p><strong>All of the functionality in the Source Available Fusion</strong></p>
</li>
<li>
<p>Additional capabilities which are derived from proprietary code (such as the <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/the-levels-of-sql-comprehension#level-2-compiling">Level 2 SQL Comprehension</a> required to compile and type-check your SQL).</p>
</li>
</ul>
<p>As long as you comply with the three restrictions in ELv2,</p>
<ul>
<li>✅&nbsp;You can&nbsp;adopt the binary into your data workflows without dbt Labs' involvement</li>
<li>❌&nbsp;But you cannot see or modify the code itself</li>
</ul>
<p><strong>The vast majority of existing dbt Core users that adopt the freely distributed components of Fusion should use the binary to do so, rather than compiling it from source code.</strong> The binary has the same permissions but more capabilities (and it saves you from having to compile it yourself). You can use it internally at your company for free, even if you are not a dbt Labs customer.</p>
<h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="using-the-dbt-fusion-engine-with-a-commercial-agreement">Using the dbt Fusion engine with a commercial agreement<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-fusion-engine-components#using-the-dbt-fusion-engine-with-a-commercial-agreement" class="hash-link" aria-label="Direct link to Using the dbt Fusion engine with a commercial agreement" title="Direct link to Using the dbt Fusion engine with a commercial agreement">​</a></h3>
<p>Artifact type: Precompiled binary and managed service</p>
<p>Available at: <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/docs/local/install-dbt?version=2">Download binary</a> and <a href="http://getdbt.com/signup" target="_blank" rel="noopener noreferrer">sign up for the service</a></p>
<p>License: ELv2 (binary) and Proprietary (service)</p>
<p>Organizations who <em>do</em> have a commercial agreement will unlock even more capabilities, but they'll use the exact same publicly-released binary discussed above. If you want to start using platform features, <a href="https://docs.getdbt.com/docs/mesh/govern/project-dependencies" target="_blank" rel="noopener noreferrer">such as dbt Mesh</a>, all you need to do is <a href="https://docs.getdbt.com/docs/platform/configure-dbt-cli#configure-the-dbt-cli" target="_blank" rel="noopener noreferrer">download a configuration file</a>. <em>(Joel commentary - As someone who has been juggling the dbt Cloud CLI alongside dbt Core for the last couple of years, I cannot overstate how thrilled I am by this.)</em></p>
<p>Obviously there's additional cloud-backed services necessary to deliver platform-specific features, such as State-Aware Orchestration. That code is proprietary and governed by your agreement with dbt Labs.</p>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="other-pieces-of-the-puzzle">Other pieces of the puzzle<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-fusion-engine-components#other-pieces-of-the-puzzle" class="hash-link" aria-label="Direct link to Other pieces of the puzzle" title="Direct link to Other pieces of the puzzle">​</a></h2>
<p>The dbt Fusion engine is the headline act, but its underlying technologies can be mixed and matched in a variety of ways.</p>
<h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="the-dbt-vs-code-extension-and-language-server">The dbt VS Code Extension and Language Server<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-fusion-engine-components#the-dbt-vs-code-extension-and-language-server" class="hash-link" aria-label="Direct link to The dbt VS Code Extension and Language Server" title="Direct link to The dbt VS Code Extension and Language Server">​</a></h3>
<p>Artifact type: Precompiled binaries</p>
<p>How to access: <a href="https://marketplace.visualstudio.com/items?itemName=dbtLabsInc.dbt" target="_blank" rel="noopener noreferrer">Install on the VS Code marketplace</a></p>
<p>License: Proprietary</p>
<p>The dbt VS Code extension is one of the first product experiences built on top of Fusion. It is not <em>part</em> of Fusion, it is <em>powered</em> by Fusion and is part of the wider dbt platform's offerings (with a generous free tier). Specifically, the VS Code extension interacts with another brand-new binary, the dbt <a href="https://microsoft.github.io/language-server-protocol/" target="_blank" rel="noopener noreferrer">Language Server</a>.</p>
<p>The Language Server is built on top of a subset of the technology powering the extended Fusion engine: as an example, it can quickly compile SQL and interact with databases, but it defers to the dbt binary when it's time to actually run a model.</p>
<link href="/css/featherlight-styles.css" type="text/css" rel="stylesheet"><div class="
          docImage_EYbW
          
          
          
          
        "><span><a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-fusion-engine-components#" data-featherlight="/img/blog/2025-05-28-dbt-fusion-engine-components/vscode-ext-binary-roles.png"><img data-toggle="lightbox" alt="The VS Code extension interacts with the Language Server to understand your SQL, and the Fusion binary to execute your SQL." title="The VS Code extension interacts with the Language Server to understand your SQL, and the Fusion binary to execute your SQL." src="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/img/blog/2025-05-28-dbt-fusion-engine-components/vscode-ext-binary-roles.png?v=2"></a></span><span class="title_aGrV">The VS Code extension interacts with the Language Server to understand your SQL, and the Fusion binary to execute your SQL.</span></div>
<h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="the-dbt-authoring-layer">The dbt Authoring Layer<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-fusion-engine-components#the-dbt-authoring-layer" class="hash-link" aria-label="Direct link to The dbt Authoring Layer" title="Direct link to The dbt Authoring Layer">​</a></h3>
<p>Artifact type: JSON Schema definitions</p>
<p>Available at: Git repos for <a href="https://github.com/dbt-labs/dbt-jsonschema" target="_blank" rel="noopener noreferrer">input files</a> and <a href="https://github.com/dbt-labs/schemas.getdbt.com" target="_blank" rel="noopener noreferrer">output artifacts</a></p>
<p>License: Apache 2.0</p>
<p>When you think of dbt, you're probably thinking of a combination of the Engine (described above) and the Authoring Layer.</p>
<p>The Authoring Layer is made up of everything necessary to define the <em>what</em> of a dbt project: things like the <strong>YAML specs, Artifact specs, CLI commands and flags</strong>, and <strong>macro signatures</strong>. As the user interface to dbt, the authoring layer is standard between Core and Fusion, although the Fusion engine does not include support for various behaviours and functions deprecated in earlier releases of dbt Core.</p>
<p>For the first time, we're releasing a series of definitive JSON schemas, <em>backed by the code in dbt Core and Fusion</em>, that encapsulate the acceptable content of dbt's various YAML files. These are Apache 2.0-licensed and will be particularly helpful for other tools integrating with dbt projects.</p>
<p>This joins the existing JSON schemas defining the shape of dbt's output artifacts (e.g. <code>manifest.json</code>). As we stabilize Fusion's metadata output (logging and artifacts) on the path to GA, we will update the published schemas.</p>
<h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="dbt-fusion-engine-adapters">dbt Fusion engine adapters<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-fusion-engine-components#dbt-fusion-engine-adapters" class="hash-link" aria-label="Direct link to dbt Fusion engine adapters" title="Direct link to dbt Fusion engine adapters">​</a></h3>
<p>Artifact type: Source code</p>
<p>Available at: Initial code in <a href="https://github.com/dbt-labs/dbt-fusion" target="_blank" rel="noopener noreferrer"><code>dbt-fusion</code> repo</a>, with more to come</p>
<p>License: Apache 2.0 (later this year)</p>
<p>Adapters are responsible for two key tasks:</p>
<ul>
<li>Knowing how to create the appropriate SQL commands (via macros and materializations) for a data platform</li>
<li>Connecting to that target data platform and sending it SQL commands</li>
</ul>
<p>Much like Fusion is the next generation engine for dbt, we also needed next-generation <em>adapters</em> for dbt. These adapters are written in Rust and built on the Apache Arrow standard.</p>
<p>The templating of SQL commands largely carries over from macros in the dbt Core adapters. Database connectivity is another story, the dbt Fusion engine cannot use the Python classes present in each adapter, for reasons both practical and performance-related.</p>
<p>Enter the Apache Arrow ecosystem at large, and the new <a href="https://arrow.apache.org/adbc/current/index.html" target="_blank" rel="noopener noreferrer">ADBC API</a> in particular. ADBC is a future-looking platform for database connectivity, and we are leaning into it heavily with these Fusion adapters.</p>
<p>Because the ADBC standard is extremely new, not all databases are compatible with ADBC yet, and using ADBC in a Rust client isn't easy. To solve both problems, we have created a Rust client library, <code>XDBC</code> that:</p>
<ul>
<li>Supports ODBC connections to databases where Arrow is not yet provided as an output</li>
<li>Provides generic methods for creating and managing connections to databases</li>
<li>Is useful for anyone who wants to build data tooling in Rust, inside or outside of the dbt ecosystem</li>
</ul>
<p>All of this will be open-sourced under the Apache 2.0 license later this year, namely:</p>
<ul>
<li>Fusion adapters we have created</li>
<li>The XDBC library</li>
<li>We'll also continue upstreaming improvements to Apache Arrow's ADBC project</li>
</ul>
<h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="antlr-grammars">ANTLR Grammars<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-fusion-engine-components#antlr-grammars" class="hash-link" aria-label="Direct link to ANTLR Grammars" title="Direct link to ANTLR Grammars">​</a></h3>
<p>Artifact type: g4 files</p>
<p>Available at: (repo to come, in the meantime you can discuss this in #dbt-fusion-engine in the dbt Slack)</p>
<p>License: Apache 2.0 (later this year)</p>
<p><a href="https://www.antlr.org/" target="_blank" rel="noopener noreferrer">ANTLR</a> grammars are the formal language specifications that let Fusion <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/sql-comprehension-technologies">parse</a> every SQL statement across multiple dialects. Specifically, ANTLR takes in these declarative, high level grammars and uses them to generate a parser. The grammars have wide utility anywhere it's necessary to parse SQL – not just in Fusion – and we're releasing them as Apache 2 to enable the Community and others in the data ecosystem to build on top of them.</p>
<p>Most ANTLR grammars are only applicable to a single dialect, but the SDF team created a system which makes it possible to define a shared base grammar and generate each warehouse's g4 file from there. This halves the amount of work required to support a new dialect at the level of precision and robustness required.</p>
<h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="dbt-jinja">dbt-jinja<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-fusion-engine-components#dbt-jinja" class="hash-link" aria-label="Direct link to dbt-jinja" title="Direct link to dbt-jinja">​</a></h3>
<p>Artifact type: Source code</p>
<p>Available at: <a href="https://github.com/dbt-labs/dbt-fusion/tree/main/dbt-jinja" target="_blank" rel="noopener noreferrer">A subdirectory of the dbt-fusion repo</a> (but there's still work to do before it's easy to use outside of the Fusion repository)</p>
<p>License: Apache 2.0</p>
<p>Since Fusion is completely Rust-based, while Jinja is a Python project, we needed a completely new way to render all the Jinja spread through users' projects. We started by switching to <a href="https://github.com/mitsuhiko/minijinja" target="_blank" rel="noopener noreferrer">minijinja</a>: a Rust port of a subset of the original Jinja project, written by Jinja's original maintainer.</p>
<p>This subset of coverage wasn't enough to support existing dbt projects, so we created Rust-native implementations of the majority of these missing features. This achieved the best of both worlds: significant performance improvements while maintaining compatibility with users' existing codebases.</p>
<p>dbt-jinja is the most feature-complete implementation of Jinja in Rust, and is available with an Apache 2.0 license today, with a more formal release (documentation etc) later this year. It's useful whether you're building tooling to operate on top of dbt projects, or working on something completely different which just needs to render Jinja quickly.</p>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="how-do-i-engage-with-these-components">How do I engage with these components?<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-fusion-engine-components#how-do-i-engage-with-these-components" class="hash-link" aria-label="Direct link to How do I engage with these components?" title="Direct link to How do I engage with these components?">​</a></h2>
<p>Our <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/community/resources/contributor-expectations">Contributors' Principles</a> remain: Building dbt is a team sport!</p>
<ul>
<li>If you want to open a PR against publicly-viewable code, you can.</li>
<li>If you want to open issues describing bugs during the Fusion engine's beta period, you can. (This is probably one of the highest-leverage things you can do!)</li>
<li>If you want to open a discussion and pitch a new way to use dbt more effectively in our new SQL-aware world, you can.</li>
<li>If you want to move upstream, and contribute to the standards underlying the dbt Fusion engine like Arrow, ADBC, Iceberg, or DataFusion, you can. You might see some familiar faces while you're there!</li>
<li>If you just want to let dbt get better and better in the background, you can do that too.</li>
<li>Want to get involved in the team building this? If the components here are uniquely interesting to you, email <a href="mailto:careers.fusion@dbtlabs.com" target="_blank" rel="noopener noreferrer">careers.fusion@dbtlabs.com</a>.</li>
</ul>
<p>If you need a hand wrapping your head around any of these new components, drop by #dbt-fusion-engine in the Community Slack - we'd love to chat.</p>]]></content>
        <author>
            <name>Jason Ganz</name>
        </author>
        <author>
            <name>Joel Labes</name>
        </author>
        <category label="analytics craft" term="analytics craft"/>
        <category label="data ecosystem" term="data ecosystem"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Path to GA: How the dbt Fusion engine rolls out from beta to production]]></title>
        <id>https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-fusion-engine-path-to-ga</id>
        <link href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-fusion-engine-path-to-ga"/>
        <updated>2025-05-28T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[We're moving quickly to enable as many teams as possible to start using the new dbt Fusion engine. Check out our roadmap and learn how to follow our progress.]]></summary>
        <content type="html"><![CDATA[<p>Today, we announced that the dbt Fusion engine is <a href="https://getdbt.com/blog/get-to-know-the-new-dbt-fusion-engine-and-vs-code-extension" target="_blank" rel="noopener noreferrer">available in beta</a>.</p>
<ul>
<li>If Fusion works with your project today, great! You're in for a treat 😄</li>
<li>If it's your first day using dbt, welcome! You should start on Fusion — you're in for a treat too.</li>
</ul>
<p>Today is Launch Day —&nbsp;the first day of a new era: the Age of Fusion. We expect many teams with existing projects will encounter at least one issue that will prevent them from adopting the dbt Fusion engine in production environments. That's ok!</p>
<p>We're moving quickly to unblock more teams, and we are committing that by the time Fusion reaches General Availability:</p>
<ul>
<li>We will support Snowflake, Databricks, BigQuery, Redshift&nbsp;—&nbsp;and likely also Athena, Postgres, Spark, and Trino — with the new <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-fusion-engine-components#dbt-fusion-engine-adapters">Fusion Adapter pattern</a>.</li>
<li>We will have coverage for (basically) all dbt Core functionality. Some things are impractical to replicate outside of Python, or so seldom-used that we'll be more reactive than proactive. On the other hand, many existing dbt Core behaviours will be improved by the unique capabilities of the dbt Fusion engine, such as speed and SQL comprehension. You'll see us talk about this in relevant GitHub issues, many of which we've linked below.</li>
<li>The source-available <code>dbt-fusion</code> repository will contain more total functionality than what is available in dbt Core today. (<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-fusion-engine-components#ways-to-access">Read more about this here</a>.)</li>
<li>The developer experience will be even speedier and more intuitive.</li>
</ul>
<p>These statements aren't true yet —&nbsp;but you can see where we're headed. That's what betas are for, that's the journey we're going on together, and that's why we want to have you all involved.</p>
<p><strong>We will be adding functionality rapidly over the coming weeks.</strong> In particular, keep an eye out for Databricks, BigQuery and Redshift support (in that order) in the coming weeks.</p>
<p>The most popular dbt Labs packages (<code>dbt_utils</code>, <code>audit_helper</code>, <code>dbt_external_tables</code>, <code>dbt_project_evaluator</code>) are already compatible with Fusion. Some external packages may not work out of the box, but we plan to work with package maintainers to get them ready &amp; working on Fusion.</p>
<p>So when is Fusion going to be GA? We're targeting later this year for full feature parity, but we're also hoping to approach it asymptotically&nbsp;—&nbsp;meaning that many existing dbt users ca start adopting Fusion much sooner.</p>
<p>During the beta period, you may run into unanticipated (and anticipated) issues when trying to run your project on Fusion. Please share any issues in the <a href="https://github.com/dbt-labs/dbt-fusion" target="_blank" rel="noopener noreferrer">dbt-fusion</a> repository or on Slack in <a href="https://getdbt.slack.com/archives/C088YCAB6GH" target="_blank" rel="noopener noreferrer">#dbt-fusion-engine</a>, and we'll do our best to to unblock you.</p>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="can-i-use-fusion-for-my-dbt-project-today">Can I use Fusion for my dbt project today?<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-fusion-engine-path-to-ga#can-i-use-fusion-for-my-dbt-project-today" class="hash-link" aria-label="Direct link to Can I use Fusion for my dbt project today?" title="Direct link to Can I use Fusion for my dbt project today?">​</a></h2>
<p>Maybe! The biggest first question: "Is your adapter supported yet?" (If not, sit tight, we're working fast!) If so, then it depends on the exact matrix of features you currently use in your dbt project.</p>
<p>You may be able to start using Fusion immediately, may need to make (mostly automatic) modifications to your project to resolve deprecations, or your project may not <em>yet</em> be parsable at all:</p>
<div class="filterableTableContainer_mhtg"><table style="display:none"><thead><tr><th>State</th><th>Description</th><th>Workaround</th><th>Resolvable by</th></tr></thead><tbody><tr><td>Unblocked</td><td>You can adopt the dbt Fusion engine with no changes to your project</td><td></td><td></td></tr><tr><td>Soft blocked</td><td>Your project parses successfully but relies on not-yet-implemented functionality</td><td>Don't invoke unsupported functions or build unsupported models</td><td>dbt Labs</td></tr><tr><td>Hard blocked by deprecations</td><td>Your project contains <a href="https://www.getdbt.com/blog/how-to-get-ready-for-the-new-dbt-engine" target="_blank" rel="noopener noreferrer">functionality deprecated in dbt Core v1.10</a></td><td>Resolve deprecations with the <a href="https://github.com/dbt-labs/dbt-autofix" target="_blank" rel="noopener noreferrer">dbt-autofix script</a> or workflow in dbt Studio</td><td>You</td></tr><tr><td>Hard blocked by known parse issues</td><td>Your project contains Python models or uses a not-yet-supported adapter</td><td>Temporarily remove Python models</td><td>dbt Labs</td></tr><tr><td>Hard blocked by unknown parse issues</td><td>Your project is probably doing something surprising with Jinja</td><td>Create an issue, consider modifying impacted code</td><td>You &amp; dbt Labs</td></tr></tbody></table><div class="tableWrapper_oiMt"><div class="searchBar_xnmH"><div class="searchContainer_fLyJ"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M416 208c0 45.9-14.9 88.3-40 122.7L502.6 457.4c12.5 12.5 12.5 32.8 0 45.3s-32.8 12.5-45.3 0L330.7 376c-34.4 25.2-76.8 40-122.7 40C93.1 416 0 322.9 0 208S93.1 0 208 0S416 93.1 416 208zM208 352a144 144 0 1 0 0-288 144 144 0 1 0 0 288z"></path></svg><input type="text" placeholder="Search table..." class="searchInput_xT8h" aria-label="Search table" value=""></div></div><table class="filterableTable_QAKT"><thead><tr></tr></thead><tbody><tr><td colspan="5" style="text-align:center;padding:20px">Loading table...</td></tr></tbody></table></div></div>
<p>We're continuously removing blockers to Fusion adoption on a rolling basis during this beta period and in the leadup to a broader release. The rest of this post will go deeper into the four thematic criteria we set out above:</p>
<ul>
<li>Adapter coverage</li>
<li>Feature coverage</li>
<li>Source-available code publishing</li>
<li>Developer experience improvements</li>
</ul>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="requirement-for-ga-adapter-coverage">Requirement for GA: Adapter Coverage<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-fusion-engine-path-to-ga#requirement-for-ga-adapter-coverage" class="hash-link" aria-label="Direct link to Requirement for GA: Adapter Coverage" title="Direct link to Requirement for GA: Adapter Coverage">​</a></h2>
<h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="databricks-bigquery-and-redshift">Databricks, BigQuery and Redshift<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-fusion-engine-path-to-ga#databricks-bigquery-and-redshift" class="hash-link" aria-label="Direct link to Databricks, BigQuery and Redshift" title="Direct link to Databricks, BigQuery and Redshift">​</a></h3>
<p>dbt Fusion's adapters are now based on the <a href="https://arrow.apache.org/adbc/current/driver/status.html" target="_blank" rel="noopener noreferrer">ADBC standard</a>, a modern, high-performance Apache project optimised for columnar analytical databases.</p>
<p>dbt Labs has developed new ADBC-compatible drivers (and a <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-fusion-engine-components#dbt-fusion-engine-adapters">supporting framework, XDBC</a>) to complement the existing, stable Snowflake driver.</p>
<p><strong>Target release dates:</strong> We expect to add support for <a href="https://github.com/dbt-labs/dbt-fusion/issues/4" target="_blank" rel="noopener noreferrer">Databricks</a>, <a href="https://github.com/dbt-labs/dbt-fusion/issues/5" target="_blank" rel="noopener noreferrer">BigQuery</a>, and <a href="https://github.com/dbt-labs/dbt-fusion/issues/6" target="_blank" rel="noopener noreferrer">Redshift</a> (in that order) in the coming weeks.</p>
<p>Where possible, Fusion adapters will support the same authentication methods and connection/credential configurations as dbt Core adapters. We've also heard loud &amp; clear feedback from dbt platform customers who have beta-tested the Fusion CLI —&nbsp;we want to figure out a way for Fusion CLI to use connection setup (config/creds) from the platform for local runs (<a href="https://github.com/dbt-labs/dbt-fusion/issues/23" target="_blank" rel="noopener noreferrer">tracking issue</a>).</p>
<h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="athena-postgres-spark-and-trino">Athena, Postgres, Spark and Trino<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-fusion-engine-path-to-ga#athena-postgres-spark-and-trino" class="hash-link" aria-label="Direct link to Athena, Postgres, Spark and Trino" title="Direct link to Athena, Postgres, Spark and Trino">​</a></h3>
<p>We're aiming to support these adapters later in the year, prior to GA. Check each adapter's tracking issue (<a href="https://github.com/dbt-labs/dbt-fusion/issues/39" target="_blank" rel="noopener noreferrer">Trino</a>, <a href="https://github.com/dbt-labs/dbt-fusion/issues/39" target="_blank" rel="noopener noreferrer">Athena</a>, <a href="https://github.com/dbt-labs/dbt-fusion/issues/38" target="_blank" rel="noopener noreferrer">Spark</a>, and <a href="https://github.com/dbt-labs/dbt-fusion/issues/31" target="_blank" rel="noopener noreferrer">Postgres</a>) for specific timelines.</p>
<h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="custom-adapters">Custom adapters<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-fusion-engine-path-to-ga#custom-adapters" class="hash-link" aria-label="Direct link to Custom adapters" title="Direct link to Custom adapters">​</a></h3>
<p>The short answer: Fusion's new adapter format could be extended to support community development of third-party adapters, but it's not on the near-term roadmap before GA (<a href="https://github.com/dbt-labs/dbt-fusion/issues/46" target="_blank" rel="noopener noreferrer">tracking issue</a>).</p>
<p>The longer answer: Fusion now downloads necessary drivers (part of the adapter stack) on-demand. This dynamic linking requires the drivers to be signed by dbt Labs, meaning that we need to have a system in place to review contributions of new drivers and ensure their security.</p>
<p>In the meantime, if you want to migrate a supported project to the dbt Fusion engine but have a dependency on another project using a custom adapter, you can use a <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/docs/deploy/hybrid-setup">Hybrid project</a> to have <span>dbt Core</span> execute the unsupported part of the pipeline and then publish artifacts for downstream projects to consume.</p>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="requirement-for-ga-feature-coverage">Requirement for GA: Feature coverage<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-fusion-engine-path-to-ga#requirement-for-ga-feature-coverage" class="hash-link" aria-label="Direct link to Requirement for GA: Feature coverage" title="Direct link to Requirement for GA: Feature coverage">​</a></h2>
<p>Feature coverage includes ensuring documented features work as expected, as well as (where possible) supporting undocumented "accidental" features.</p>
<p>Most of the time, even if your project uses an unimplemented feature, you can still take Fusion for a spin. This is because as long as your project parses, you can just skip unsupported models.</p>
<h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="known-unimplemented-features">Known unimplemented features<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-fusion-engine-path-to-ga#known-unimplemented-features" class="hash-link" aria-label="Direct link to Known unimplemented features" title="Direct link to Known unimplemented features">​</a></h3>
<h4 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="python-models">Python models<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-fusion-engine-path-to-ga#python-models" class="hash-link" aria-label="Direct link to Python models" title="Direct link to Python models">​</a></h4>
<p>Python models are the one exception to that "just skip them" advice. The dbt Fusion engine does not currently support parsing Python models, which means it can not extract refs or configs inside the files. Instead of potentially building models out of DAG order, <strong>we've chosen to not support Python models at all for now</strong>. They're coming back though - <a href="https://github.com/dbt-labs/dbt-fusion/issues/3" target="_blank" rel="noopener noreferrer">check out the issue</a> for details.</p>
<h4 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="breadth-of-materialization-support">Breadth of Materialization Support<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-fusion-engine-path-to-ga#breadth-of-materialization-support" class="hash-link" aria-label="Direct link to Breadth of Materialization Support" title="Direct link to Breadth of Materialization Support">​</a></h4>
<p>As of today we support the most common materializations: <code>table</code>, <code>view</code>, <code>incremental</code>, <code>ephemeral</code> for models —&nbsp;plus the materializations underlying snapshots, seeds, and tests. Other native strategies (like <a href="https://github.com/dbt-labs/dbt-fusion/issues/12" target="_blank" rel="noopener noreferrer">microbatch incremental models</a>, <a href="https://github.com/dbt-labs/dbt-fusion/issues/28" target="_blank" rel="noopener noreferrer">iceberg tables</a>, <a href="https://github.com/dbt-labs/dbt-fusion/issues/27" target="_blank" rel="noopener noreferrer">materialized views/dynamic tables</a>, or <a href="https://github.com/dbt-labs/dbt-fusion/issues/15" target="_blank" rel="noopener noreferrer">stored test failures</a>) as well as <a href="https://github.com/dbt-labs/dbt-fusion/issues/17" target="_blank" rel="noopener noreferrer">custom materializations</a> are on the roadmap — check their respective issues to see when.</p>
<p>It's worth reiterating here: Even if you have models that rely on not-yet-supported materialization strategies, you can still try the dbt Fusion engine in the rest of your project. The rest of your DAG will build as normal, but unsupported strategies will raise an error if they are included in scope of <code>dbt build</code> or <code>dbt run</code>.</p>
<p>To exclude those nodes, use a command like</p>
<ul>
<li><code>dbt build --exclude config.materialized:my_custom_mat</code></li>
<li><code>dbt build --exclude config.incremental_strategy:microbatch</code></li>
</ul>
<h4 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="other-common-features">Other common features<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-fusion-engine-path-to-ga#other-common-features" class="hash-link" aria-label="Direct link to Other common features" title="Direct link to Other common features">​</a></h4>
<p>Did you know that there are over 400 documented features of dbt? <a href="https://github.com/dbeatty10" target="_blank" rel="noopener noreferrer">Doug</a> does, because he had to put them all into a Notion database.</p>
<p>Fusion already supports two-thirds of them, and we have a plan for the rest. You can follow along at <a href="https://github.com/dbt-labs/dbt-fusion/issues" target="_blank" rel="noopener noreferrer">the <code>dbt-fusion</code> repo</a>, where there are issues to track the outstanding behaviours. There's also a rough set of milestones attached, but those are subject to reordering as more teams start using Fusion and giving feedback.</p>
<p>Some of the most relevant ones include:</p>
<ul>
<li><a href="https://github.com/dbt-labs/dbt-fusion/issues/13" target="_blank" rel="noopener noreferrer">Exposures</a></li>
<li>A new <a href="https://github.com/dbt-labs/dbt-fusion/issues/7" target="_blank" rel="noopener noreferrer">stable logging system</a></li>
<li>A new <a href="https://github.com/dbt-labs/dbt-fusion/issues/9" target="_blank" rel="noopener noreferrer">local documentation experience</a> that replaces dbt-docs (!)</li>
<li><a href="https://github.com/dbt-labs/dbt-fusion/issues/10" target="_blank" rel="noopener noreferrer">Programmatic invocations</a></li>
<li><a href="https://github.com/dbt-labs/dbt-fusion/issues/25" target="_blank" rel="noopener noreferrer">Model governance</a> (contracts, constraints, access, deprecation_date)</li>
<li>A grab bag of CLI commands like <a href="https://github.com/dbt-labs/dbt-fusion/issues/22" target="_blank" rel="noopener noreferrer"><code>dbt clone</code></a>, <a href="https://github.com/dbt-labs/dbt-fusion/issues/33" target="_blank" rel="noopener noreferrer"><code>state:modified.subselector</code></a>, <a href="https://github.com/dbt-labs/dbt-fusion/issues/34" target="_blank" rel="noopener noreferrer"><code>--empty</code></a>, ...</li>
</ul>
<p>It's worth noting that <em>resolution</em> doesn't necessarily mean identical behaviours. As a couple of examples:</p>
<ul>
<li>Many of these behaviours have not been implemented yet because the Fusion engine introduces new capabilities, above all SQL comprehension, that we will leverage to provide a superior experience. A direct port-over of the feature would miss the point.</li>
<li>Others (like the events and logging system) are tightly coupled to dbt Core's Python roots — they're worth a rethink, and not worth shooting for exact 100% conformance</li>
</ul>
<p>Here's a point-in-time snapshot of how we expect to tackle the known remaining work. Please refer to the <a href="https://github.com/dbt-labs/dbt-fusion/issues" target="_blank" rel="noopener noreferrer">repository's issues page</a> as the source of truth:</p>
<link href="/css/featherlight-styles.css" type="text/css" rel="stylesheet"><div class="
          docImage_EYbW
          
          
          
          
        " style="max-width:100%"><span><a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-fusion-engine-path-to-ga#" data-featherlight="/img/blog/2025-05-28-dbt-fusion-engine-path-to-ga/indicative-timeline.png"><img data-toggle="lightbox" alt="An indication of the dbt Fusion engine's path to GA" title="An indication of the dbt Fusion engine's path to GA" src="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/img/blog/2025-05-28-dbt-fusion-engine-path-to-ga/indicative-timeline.png?v=2"></a></span><span class="title_aGrV">An indication of the dbt Fusion engine's path to GA</span></div>
<h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="surprise-unimplemented-features">Surprise unimplemented features<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-fusion-engine-path-to-ga#surprise-unimplemented-features" class="hash-link" aria-label="Direct link to Surprise unimplemented features" title="Direct link to Surprise unimplemented features">​</a></h3>
<p>Did you know that there are also over a bajillion <em>undocumented</em> features of dbt? Since March, we've been validating the new engine's parser against projects orchestrated by the dbt platform, which has flagged hundreds of divergent behaviours and common parse bugs.</p>
<p>But we also know there is a long tail of behaviours that will only arise in the wild, and that the easiest way to get to the bottom of them will be to work with users.</p>
<p>This work will be ongoing, alongside feature support. When you start using the Fusion engine, please <a href="https://github.com/dbt-labs/dbt-fusion/issues" target="_blank" rel="noopener noreferrer">open an issue</a> if you hit an unexpected error — and please include a basic project that reproduces the error, so we can fix it!</p>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="requirement-for-ga-the-source-available-dbt-fusion-codebase-is-better-than-dbt-core-for-most-use-cases">Requirement for GA: The Source-available <code>dbt-fusion</code> codebase is better than <code>dbt-core</code> for most use cases<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-fusion-engine-path-to-ga#requirement-for-ga-the-source-available-dbt-fusion-codebase-is-better-than-dbt-core-for-most-use-cases" class="hash-link" aria-label="Direct link to requirement-for-ga-the-source-available-dbt-fusion-codebase-is-better-than-dbt-core-for-most-use-cases" title="Direct link to requirement-for-ga-the-source-available-dbt-fusion-codebase-is-better-than-dbt-core-for-most-use-cases">​</a></h2>
<p>By GA, the <a href="https://github.com/dbt-labs/dbt-fusion" target="_blank" rel="noopener noreferrer"><code>dbt-fusion</code> repository</a> will have the necessary (and fully source-available) components to compile a functional engine for the vast majority of dbt Core projects —&nbsp;and a faster one at that. That means that you will always have the ability to compile, use, and modify this code itself, without requiring access to the dbt Labs provided binary (although we think you'll probably just want to use the binary, for reasons detailed in the <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-fusion-engine-components">Components of the dbt Fusion engine</a> post).</p>
<p>So far, we've released the code necessary to self-compile a dbt binary that can run <code>dbt deps</code> and <code>dbt parse</code>. Throughout the beta period we will continue to prepare more code for use by those who want to view, contribute to, or modify the code for their own purposes, including what's necessary for the rest of the commands to work.</p>
<p>Beyond just the code necessary to produce a complete dbt binary, we've also committed to open-sourcing several of the underlying library components (such as dbt-jinja, dbt-serde-yaml, and the grammars necessary to produce a high-performance SQL parser). Again, check out the <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-fusion-engine-components">Components of the dbt Fusion engine</a> post for the details.</p>
<p>Some behaviours that worked in dbt Core won't have an equivalent in this new codebase. The most obvious examples are those which depended on the vagaries of Python: arbitrary callbacks on the EventManager (there's no longer an EventManager on which to register a callback!), the experimental <a href="https://github.com/dbt-labs/dbt-core/blob/1.latest/core/dbt/plugins/manager.py" target="_blank" rel="noopener noreferrer">plugins system</a> (dynamic loading of binaries works completely differently in Rust and would require signing), or the dbt templater in SQLFluff (which hooked into dbt Core beyond the exposed interfaces - although we plan to build a <a href="https://github.com/dbt-labs/dbt-fusion/issues/11" target="_blank" rel="noopener noreferrer">fast linter ourselves</a>).</p>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="requirement-for-ga-the-dx-rocks">Requirement for GA: The DX rocks<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-fusion-engine-path-to-ga#requirement-for-ga-the-dx-rocks" class="hash-link" aria-label="Direct link to Requirement for GA: The DX rocks" title="Direct link to Requirement for GA: The DX rocks">​</a></h2>
<h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="more-speed">More speed<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-fusion-engine-path-to-ga#more-speed" class="hash-link" aria-label="Direct link to More speed" title="Direct link to More speed">​</a></h3>
<p>Invocations powered by the dbt Fusion engine are already significantly faster than the same invocation in dbt Core, but there's more to do here! We know that there is still a lot of low-hanging fruit, and by GA we expect to see tasks like full project compilation complete at least twice as fast for many projects.</p>
<p>If you do some benchmarking, we're particularly interested in any situations where Fusion "pauses" on a single file for a couple of seconds. Some other things to keep in mind:</p>
<ul>
<li>Writing very large manifests is pretty slow, no matter what. Try including <code>--no-write-json</code>. We're wondering whether it makes sense to have a trimmed-down manifest by default. What do you think?</li>
<li>The <code>dbt compile</code> command involves more work in Fusion than in dbt Core, because it's doing full SQL validation. To compare <em>just</em> the SQL rendering step (the equivalent of dbt Core's <code>compile</code> command), you can try <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/docs/build/about-static-analysis">turning off static analysis</a> with the CLI flag <code>--static-analysis off</code>.</li>
</ul>
<p>As a sign of what's possible, take note of the incremental recompilation used to provide real-time feedback in the VS Code extension.</p>
<h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="a-more-info-dense-console-output">A more info-dense console output<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-fusion-engine-path-to-ga#a-more-info-dense-console-output" class="hash-link" aria-label="Direct link to A more info-dense console output" title="Direct link to A more info-dense console output">​</a></h3>
<p>While we were preparing for the beta release, we kept the Fusion CLI output intentionally verbose — it displays <em>everything</em> that's happening, which means errors and warnings can be pushed out of view by other status updates. We're already in the process of <a href="https://github.com/dbt-labs/dbt-fusion/issues/52" target="_blank" rel="noopener noreferrer">clearing this up a bit</a>, and we've got some funny ideas about the possibility of progress bars. However we do it, the goal should be that you see the log lines about things that need attention, and not much more.</p>
<h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="your-idea-here">Your idea here<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-fusion-engine-path-to-ga#your-idea-here" class="hash-link" aria-label="Direct link to Your idea here" title="Direct link to Your idea here">​</a></h3>
<p>What feels <em>off</em> when you're using dbt Fusion? Tell us all about it — if you've got a clear idea for what's wrong and what it should be instead, feel free to jump straight to a GitHub issue. Bonus points if you've got a minimal repro project.</p>
<p>If you need to kick an idea around before opening an issue, we'll also be actively checking in on #dbt-fusion-engine (for high-level discussions) and #dbt-fusion-engine-migration (to get into the weeds of a specific bug) on Slack.</p>
<p>From now until Fusion is GA, we will be prioritizing parity with existing framework features, <em>not adding new ones.</em> Once we hit GA, we'll think about whether to transfer existing feature requests from the <code>dbt-core</code> repo to <code>dbt-fusion</code> — or maybe a third place? — stay tuned.</p>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="following-along">Following along<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-fusion-engine-path-to-ga#following-along" class="hash-link" aria-label="Direct link to Following along" title="Direct link to Following along">​</a></h2>
<p>The path to GA for Fusion is a Community-wide effort. We want to hear from you, work with you, get your ideas and feedback. Whether it is sharing a bug report, an idea for a feature or more high level thoughts and feedback, we're looking to engage with you.</p>
<ul>
<li>In Slack, we're on <a href="https://getdbt.slack.com/archives/C088YCAB6GH" target="_blank" rel="noopener noreferrer">#dbt-fusion-engine</a> and #dbt-fusion-engine-migration</li>
<li>The GitHub repo is <a href="https://github.com/dbt-labs/dbt-fusion" target="_blank" rel="noopener noreferrer">https://github.com/dbt-labs/dbt-fusion</a></li>
<li>There are a couple of dozen <em>dbt World Circuit</em> meetups happening globally during June: <a href="https://www.meetup.com/pro/dbt/" target="_blank" rel="noopener noreferrer">https://www.meetup.com/pro/dbt/</a>. (Jeremy will be speaking in Paris, Marseille, and Boston —&nbsp;come hang out!)</li>
<li>We'll be having regular office hours with a revolving cast of characters from the Developer Experience, Engineering, and Product teams. Dates will be circulated in the #dbt-fusion-engine channel.</li>
</ul>]]></content>
        <author>
            <name>Jeremy Cohen</name>
        </author>
        <author>
            <name>Joel Labes</name>
        </author>
        <category label="data ecosystem" term="data ecosystem"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Meet the dbt Fusion Engine: the new Rust-based, industrial-grade engine for dbt]]></title>
        <id>https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-fusion-engine</id>
        <link href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-fusion-engine"/>
        <updated>2025-05-28T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[The dbt Fusion engine delivers a next-gen developer experience by combining high-speed execution with deep understanding of your code.]]></summary>
        <content type="html"><![CDATA[<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="tldr-what-you-need-to-know">TL;DR: What You Need to Know<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-fusion-engine#tldr-what-you-need-to-know" class="hash-link" aria-label="Direct link to TL;DR: What You Need to Know" title="Direct link to TL;DR: What You Need to Know">​</a></h2>
<ul>
<li>dbt’s familiar authoring layer remains unchanged, but the execution engine beneath it is completely new.</li>
<li>The new engine is called the dbt Fusion engine — rewritten from the ground up in Rust based on technology <a href="https://www.getdbt.com/blog/dbt-labs-acquires-sdf-labs" target="_blank" rel="noopener noreferrer">from SDF</a>.  The dbt Fusion engine is substantially faster than dbt Core and has built in <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/the-levels-of-sql-comprehension">SQL comprehension technology</a> to power the next generation of analytics engineering workflows.</li>
<li>The dbt Fusion engine is currently in beta. You can try it today if you use Snowflake — with additional adapters coming starting in early June. Review our <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-fusion-engine-path-to-ga">path to general availability</a> (GA) and <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/guides/fusion">try the quickstart</a>.</li>
<li><strong>You do not need to be a dbt Labs customer to use Fusion - dbt Core users can adopt the dbt Fusion engine today for free in your local environment.</strong></li>
<li>You can use <span>Fusion</span> with the <a href="https://marketplace.visualstudio.com/items?itemName=dbtLabsInc.dbt" target="_blank" rel="noopener noreferrer">new dbt VS Code extension</a>, <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/docs/local/install-dbt?version=2">directly with the CLI</a>, or <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/docs/dbt-versions/upgrade-dbt-platform-version#dbt-fusion-engine">with dbt Studio</a>.</li>
<li>This is the beginning of a new era for analytics engineering. For a glimpse into what the Fusion engine is going to enable over the next 1 to 2 years, <a href="https://getdbt.com/blog/where-we-re-headed-with-the-dbt-fusion-engine" target="_blank" rel="noopener noreferrer">read this post</a>.</li>
</ul>
<p>Since its introduction in 2016, dbt has paved the way for the analytics engineering revolution. Teams worldwide have moved from ad hoc processes running customized SQL scripts into a mature analytics workflow based on the <a href="https://docs.getdbt.com/community/resources/viewpoint" target="_blank" rel="noopener noreferrer">dbt viewpoint</a>. dbt enables data practitioners to <em>work like software engineers</em>, building their analytics code as an asset to ship trusted data products faster.</p>
<p>dbt came to represent many things:</p>
<ul>
<li>A <strong>viewpoint</strong> on how analytics should be done</li>
<li>A <strong>workflow</strong> where data practitioners could put that viewpoint into action</li>
<li>A <strong>framework</strong> — dbt Core — that powered this workflow comprised of:<!-- -->
<ul>
<li>An authoring layer: The schema, spec, and definitions for a dbt project written in SQL, YML, and Jinja</li>
<li>An engine: The tooling via which the authoring layer was built and executed against a data platform, resolving templated code into executable SQL, building your dependency graph, and more.</li>
</ul>
</li>
</ul>
<link href="/css/featherlight-styles.css" type="text/css" rel="stylesheet"><div class="
          docImage_EYbW
          
          
          
          
        "><span><a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-fusion-engine#" data-featherlight="/img/blog/2025-05-28-dbt-fusion-engine/engine-and-authoring-layer.png"><img data-toggle="lightbox" alt="dbt is made up of two different things: authoring layer and engine." title="dbt is made up of two different things: authoring layer and engine." src="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/img/blog/2025-05-28-dbt-fusion-engine/engine-and-authoring-layer.png?v=2"></a></span><span class="title_aGrV">dbt is made up of two different things: authoring layer and engine.</span></div>
<p>While the authoring layer has continued to evolve nicely, giving dbt developers ever-more functionality to work with, the engine itself, dbt Core, is still built on the same technology and uses the same primary design principles that it started with in 2016. This causes two primary problems that cannot be iteratively solved:</p>
<ol>
<li>dbt Core can be <em>slow</em>.  It’s built in Python and for larger dbt projects it can become unworkable. Even for smaller projects, to power a great developer experience, users would need a step change in performance.</li>
<li>The dbt engine renders SQL, but it doesn’t <em>comprehend SQL.</em> That means that any functionality relying on specifics of SQL code was impossible to build into dbt.</li>
</ol>
<p>And so it became clear that for us to power the analytics workloads of tomorrow, we weren't going to get there with incremental improvements —&nbsp;we needed to <strong>rebuild the dbt engine from scratch</strong>. We needed:</p>
<ul>
<li>An engine built for speed.</li>
<li>An engine that <em>knows about your code.</em></li>
<li>An engine that powers the next generation of developer experience.</li>
</ul>
<p>And that engine is Fusion.</p>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="what-exactly-is-fusion">What exactly is Fusion?<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-fusion-engine#what-exactly-is-fusion" class="hash-link" aria-label="Direct link to What exactly is Fusion?" title="Direct link to What exactly is Fusion?">​</a></h2>
<p>Fusion is the new engine for dbt.</p>
<p>If the authoring layer is "what" your dbt project is supposed to do, then the engine is the "how." That includes:</p>
<ul>
<li>Rendering Jinja</li>
<li>Building dependency graphs</li>
<li>Creating artifact files</li>
<li>Communicating with databases</li>
</ul>
<p>At first glance, Fusion looks a lot like dbt Core. Your projects are built using the familiar dbt authoring layer. You still write SQL and Jinja. You still type <code>dbt run</code>. (To make it easier to try Fusion, we're also shipping with an optional <code>dbtf</code> alias, as many users have the <code>dbt</code> namespace already specified).</p>
<p>But underneath that is a layer of technical depth and rigor that is entirely new to dbt, happening at the engine layer.</p>
<p>Fusion:</p>
<ul>
<li>Is fully rewritten in Rust, enabling a <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/faster-project-parsing-with-rust">dramatically faster dbt experience</a>. Fusion does not depend on Python at all. In fact, besides the adapter macros, not a single line of code is shared between dbt Core and the dbt Fusion engine. (For long-time dbt spelunkers, we've described the new structure in a <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-fusion-engine-components">separate post</a>.)</li>
<li><a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/the-levels-of-sql-comprehension">Understands your SQL code.</a> It’s a true SQL <em>compiler</em> and gives dbt a full view on what the code in your dbt project means and how it will propagate across your entire data lineage.</li>
</ul>
<p>Based on the technology from <a href="https://www.getdbt.com/blog/dbt-labs-acquires-sdf-labs" target="_blank" rel="noopener noreferrer">SDF</a>, Fusion represents a step change increase in the technical capabilities of dbt.</p>
<link href="/css/featherlight-styles.css" type="text/css" rel="stylesheet"><div class="
          docImage_EYbW
          
          
          
          
        "><span><a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-fusion-engine#" data-featherlight="/img/blog/2025-05-28-dbt-fusion-engine/familiar-authoring-powerful-new-engine.png"><img data-toggle="lightbox" alt="Familiar Authoring Layer, Powerful New Engine." title="Familiar Authoring Layer, Powerful New Engine." src="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/img/blog/2025-05-28-dbt-fusion-engine/familiar-authoring-powerful-new-engine.png?v=2"></a></span><span class="title_aGrV">Familiar Authoring Layer, Powerful New Engine.</span></div>
<p>As a result of these capabilities, Fusion can deliver new experiences. Some of these we’re releasing today, like real-time error detection in VS Code and significant cost savings in project execution.  dbt now knows about your code!</p>
<p><strong>You probably now know enough now to head on over to the quickstart and get going</strong>, but if you want to know little more about what Fusion delivers today, keep reading.</p>
<hr>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="near-term-benefits-of-adopting-fusion">Near-term benefits of adopting Fusion<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-fusion-engine#near-term-benefits-of-adopting-fusion" class="hash-link" aria-label="Direct link to Near-term benefits of adopting Fusion" title="Direct link to Near-term benefits of adopting Fusion">​</a></h2>
<p>You can think of Fusion as the same dbt you know and love, but better and faster, and you're going to see it show up in a lot of places!</p>
<link href="/css/featherlight-styles.css" type="text/css" rel="stylesheet"><div class="
          docImage_EYbW
          
          
          
          
        "><span><a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-fusion-engine#" data-featherlight="/img/blog/2025-05-28-dbt-fusion-engine/next-gen-star.png"><img data-toggle="lightbox" alt="Functionality powered by the dbt Fusion Engine and its components" title="Functionality powered by the dbt Fusion Engine and its components" src="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/img/blog/2025-05-28-dbt-fusion-engine/next-gen-star.png?v=2"></a></span><span class="title_aGrV">Functionality powered by the dbt Fusion Engine and its components</span></div>
<p>So how and why should you adopt Fusion for your dbt project?</p>
<h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="just-the-new-fusion-powered-dbt-cli">Just the new Fusion-powered dbt CLI<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-fusion-engine#just-the-new-fusion-powered-dbt-cli" class="hash-link" aria-label="Direct link to Just the new Fusion-powered dbt CLI" title="Direct link to Just the new Fusion-powered dbt CLI">​</a></h3>
<ul>
<li><strong>Significant performance improvements:</strong> Up to 30x faster parsing and 2x quicker full-project compilation, with near-instant recompilation of single files in the VS Code Extension. We expect continued performance gains as part of the path to GA.</li>
</ul>
<h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="the-new-fusion-powered-dbt-fusion-cli--vs-code-extension">The new Fusion-powered dbt Fusion CLI + VS Code extension<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-fusion-engine#the-new-fusion-powered-dbt-fusion-cli--vs-code-extension" class="hash-link" aria-label="Direct link to The new Fusion-powered dbt Fusion CLI + VS Code extension" title="Direct link to The new Fusion-powered dbt Fusion CLI + VS Code extension">​</a></h3>
<p>But the real benefit of Fusion is not just going to be in the CLI itself — it’s in the ability to build net new product experiences that leverage Fusion’s capabilities. The first of these, unveiled today, is the VS Code extension, powered by <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/the-levels-of-sql-comprehension">dbt Fusion’s SQL Comprehension</a>. This extension could <em>only</em> be built on Fusion:</p>
<ul>
<li>It’s fast — the VS Code extension recompiles your entire dbt project in the background every time you save <em>any</em> file, as well as identifying errors instantly for the active file. For that to be workable, it needs to happen fast.</li>
<li>It understand SQL and functions as a compiler — it knows what columns exist in your project, what functions you are using and the type signature and output of those functions.</li>
</ul>
<p>There’s a whole host of features in the VS Code extension. Some early favorites:</p>
<ul>
<li>
<p><strong>Write code with confidence — live error detection and function autocomplete.</strong></p>
<ul>
<li>
<p>How many time have you hit <code>dbt run</code> only to realize that you typed <code>select * frmo</code>, misspelled a column name or tried to sum the unsummable? No more! With the LSP-powered VS Code extension, you can immediately see when pesky errors sneak into your code.</p>
<link href="/css/featherlight-styles.css" type="text/css" rel="stylesheet"><div class="
          docImage_EYbW
          
          
          
          
        "><span><a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-fusion-engine#" data-featherlight="/img/blog/2025-05-28-dbt-fusion-engine/you-wouldnt-sum-a-datetime.png"><img data-toggle="lightbox" alt="You wouldn't sum a datetime." title="You wouldn't sum a datetime." src="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/img/blog/2025-05-28-dbt-fusion-engine/you-wouldnt-sum-a-datetime.png?v=2"></a></span><span class="title_aGrV">You wouldn't sum a datetime.</span></div>
</li>
<li>
<p>Similarly — is it <code>dateadd</code> or <code>date_add</code>? And which way around do the arguments go again? Just start typing and you'll see contextual prompts and autocomplete.</p>
</li>
</ul>
</li>
<li>
<p><strong>See how the code you’ve written iteratively progresses to your transformed data:</strong> <em>Preview CTEs and viewing compiled code</em></p>
<ul>
<li>Because the VS Code extension compiles your code every time you save, you can view the compiled code from your project in real time as you’re making edits. This is a real lifesaver when working on complex macros.</li>
<li>Writing your code with CTEs allows you to modularly split up the logic in your model. The days when you swap out the <code>final</code> CTE at the end for the name of the CTE you're debugging are no more, now you can just click.</li>
</ul>
</li>
<li>
<p><strong>Traverse your project:</strong> Go-to-reference and built in lineage</p>
<ul>
<li>Need to find out how an upstream model was defined? Or where all the inputs from the model you’re working on came from? With both the ability to jump to the model and column references <em>and</em> view model and column level lineage, it’s honestly a night and day difference.</li>
</ul>
</li>
</ul>
<video width="100%" height="100%" muted="" controls=""><source src="/img/docs/extension/go-to-definition.webm" type="video/webm"></video>
<p>I could go on and on and on — there’s so much here.</p>
<p>Taken separately, these range from quality of life improvements to significant changes.</p>
<p>But taken together, it actually fundamentally changes the experience of writing your dbt code. There were just <em>so many things</em> that you had to constantly be juggling in the back of your head that are now offloaded to the extension. The sum change to the experience of writing dbt code... is exceptional. I already can’t imagine working without this.</p>
<p>Of course — there’s another technology changing the experience of writing dbt (and all) code — AI. The functionality that Fusion enables dovetails perfectly with AI-assisted coding by allowing you to vet, validate, and comprehend AI-generated code more easily. Moving forward, expect even tighter coupling between Fusion and AI-based coding assistants as the speed and rigor of Fusion will help produce higher quality AI-generated code.</p>
<p>The VS Code extension is one of our first product experiences exclusively powered by the dbt Fusion engine. The extension depends on the Language Server, and the Language Server depends on Fusion's SQL comprehension capabilities. We made the decision not to support dbt Core for the VS Code Extension because existing community-built extensions have already built as much as is possible on top of dbt Core's foundation.  To get to this next level of experience, we needed Fusion.</p>
<hr>
<h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="how-to-get-started-with-fusion">How to get started with Fusion<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-fusion-engine#how-to-get-started-with-fusion" class="hash-link" aria-label="Direct link to How to get started with Fusion" title="Direct link to How to get started with Fusion">​</a></h3>
<p>The dbt Fusion engine is currently in beta. We've written <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-fusion-engine-path-to-ga">a separate post</a> describing the path to Fusion's final release, and how you can see if your project is compatible today.</p>
<p>Whether or not you can move your existing project to Fusion today, you can jump into the VS Code extension <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/guides/fusion">using our quickstart</a> to try get a feeling for what's ahead.</p>
<ul>
<li><strong>dbt customers:</strong> Over the coming weeks, in projects eligible to start using Fusion, you’ll see a toggle in your account or receive a message from your account team. From there, <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/docs/dbt-versions/upgrade-dbt-platform-version#dbt-fusion-engine">you can activate Fusion for your environments</a>.</li>
<li><strong>To use the VS Code extension:</strong> <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/docs/install-dbt-extension">Install the "dbt" extension</a> directly from the marketplace for automated setup and head to the quickstart. This will also automatically install the Fusion-powered CLI for you.</li>
<li><strong>To use the <span>dbt CLI</span> powered by <span>Fusion</span>:</strong> Simply <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/docs/local/install-dbt?version=2">install Fusion</a></li>
</ul>
<p><em>If you are looking to migrate an existing project to Fusion, see the <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/docs/dbt-versions/core-upgrade/upgrading-to-v2">migration guide</a> —&nbsp;as well as the <a href="https://github.com/dbt-labs/dbt-autofix" target="_blank" rel="noopener noreferrer"><code>dbt-autofix</code></a> helper, which automatically addresses many of the changes needed to migrate to Fusion.</em></p>
<hr>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="whats-next">What's Next?<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-fusion-engine#whats-next" class="hash-link" aria-label="Direct link to What's Next?" title="Direct link to What's Next?">​</a></h2>
<p>Today’s launch is the start. There is much left to do over the short term and long term.</p>
<p>Moving forward we’re building many net new products and evolutions of our current products that simply wouldn’t have been possible in a pre-Fusion world. This will be particularly impactful for powering AI workflows, both to assist in the creation of high quality dbt projects and serving as the trusted interface to structured data for AI agents.</p>
<p>We’re excited to work with the Community on the evolution of Fusion. If you’ve heard talk about the early days of the dbt Community and wished you could have been around for it, you now have the opportunity to make the deep, foundational impact that is often only possible at the start of a new technical innovation cycle.</p>
<p>So get involved!</p>
<ul>
<li>Try out <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/guides/fusion">the Fusion quickstart</a></li>
<li><a href="https://github.com/dbt-labs/dbt-fusion/issues" target="_blank" rel="noopener noreferrer">Open up a GitHub issue in <code>dbt-fusion</code></a> to report a bug or participate in the path to GA</li>
<li>Join us <a href="https://www.getdbt.com/community/join-the-community" target="_blank" rel="noopener noreferrer">on Slack</a> in #dbt-fusion-engine and share your thoughts or questions</li>
<li>Head to an <a href="https://www.meetup.com/pro/dbt/" target="_blank" rel="noopener noreferrer">in-person dbt Meetup</a> — we’re hosting the dbt World Circuit 🏎️&nbsp;around the world where you can and come talk to one of us about Fusion!</li>
</ul>]]></content>
        <author>
            <name>Jason Ganz</name>
        </author>
        <category label="analytics craft" term="analytics craft"/>
        <category label="data ecosystem" term="data ecosystem"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[AI Evaluation in dbt]]></title>
        <id>https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/ai-eval-in-dbt</id>
        <link href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/ai-eval-in-dbt"/>
        <updated>2025-05-04T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[How to extend dbt quality testing to monitor AI Agentic Quality]]></summary>
        <content type="html"><![CDATA[<p><strong>The AI revolution is here—but are we ready?</strong><br>
<!-- -->Across the world, the excitement around AI is undeniable.  Discussions on large language models, agentic workflows, and how AI is set to transform every industry abound, yet real-world use cases of AI in production remain few and far between.</p>
<p>A common issue blocking people from moving AI use cases to production is an ability to evaluate the validity of AI responses in a systematic and well governed way.
Moving AI workflows from prototype to production requires rigorous evaluation, and most organizations do not have a framework to ensure AI outputs remain high-quality, trustworthy, and actionable.</p>
<p><strong>Why AI Evaluation Matters</strong><br>
<!-- -->The more conversations we have with data teams, the clearer the problem becomes: Companies don’t want to move AI into production unless they can monitor and ensure its quality once it's there -- the fear of a ‘rogue AI’ still exceeds perceived benefits.</p>
<p>The core challenge isn’t just building AI use cases; it’s about continuously monitoring their performance and ensuring the same level of quality and reliability we’ve come to expect from other data assets.
To trust AI in production, we need structured workflows that:</p>
<ul>
<li><strong>Ensure data quality</strong> before it’s fed into AI models</li>
<li><strong>Evaluate AI-generated responses</strong> against responses known to be true</li>
<li><strong>Trigger alerts or corrective actions</strong> when AI performance drifts below acceptable thresholds</li>
</ul>
<p>Without these capabilities, AI workflows remain stuck in experimental phases, unable to meet the reliability requirements of production use cases.</p>
<p><strong>Using dbt to Build AI Evaluation Workflows</strong>
Most organizations already use dbt to transform, test and validate their data.
As an already trusted framework for data quality, it seemed natural to use dbt’s testing capabilities to evaluate and monitor AI workflows as well.</p>
<p>Let’s walk through a simple example using <strong>dbt and Snowflake Cortex</strong> for AI evaluation.</p>
<ul>
<li><strong>Ingest Data</strong> We start by uploading a dataset of IMDB movie reviews, along with human-labeled sentiment scores (positive or negative). This serves as our source of truth.</li>
<li><strong>Run AI Workflow</strong> As an simple example workflow, we use Snowflake Cortex’s sentiment analysis function, to classify each review.</li>
<li><strong>Evaluate AI Output versus Human Review</strong> We create an evaluation model in dbt that uses the Cortex Complete function to compare the AI-generated sentiment to the actual human-labeled sentiment.</li>
<li><strong>Define Pass/Fail Criteria</strong> We configure a custom dbt test to set an accuracy threshold (e.g., 75% accuracy). If AI sentiment predictions fall below this level, the test triggers a warning or error.</li>
<li><strong>Store and Visualize Results</strong> Native dbt functionality can easily store test failures in the warehouse providing traceability for further investigation, and data for reporting on AI accuracy.</li>
</ul>
<p><strong>Scaling AI Evaluation with dbt</strong><br>
<!-- -->This workflow naturally extends dbt’s native testing capabilities and leverages the powerful ability to embed Snowflake Cortex calls in SQL models.
In this way users can combine the power of Snowflake Cortex with the established governance and quality framework of dbt to address the issues stated above.</p>
<p>By using dbt to evaluate AI, organizations can apply the same rigorous testing principles they already use for data pipelines to ensure their AI models are production-ready and maintain quality and governance of all data assets centrally.</p>
<p><strong>What we Built</strong>
Let's walk through this example step by step to give you a sense of how it all works.
For this example, we start with a test data set which contains the input to our AI workflow, as well as a true measurement given by a human reviewer -- in this example our input is the text review of different movies and the <code>actual_sentiment</code> contains a -1 for negative reviews and 1 for positive reviews.
Finally we include a time stamp indicating when our AI provided the response. This time stamp will allow us to track our AI accuracy over time.</p>
<link href="/css/featherlight-styles.css" type="text/css" rel="stylesheet"><div class="
          docImage_EYbW
          
          
          
          
        " style="max-width:85%"><span><a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/ai-eval-in-dbt#" data-featherlight="/img/blog/2025-04-04-ai-evaluation-and-how-dbt-can-help/ai_eval_blog_image_one.png"><img data-toggle="lightbox" alt="our input data set, including actual sentiment" title="our input data set, including actual sentiment" src="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/img/blog/2025-04-04-ai-evaluation-and-how-dbt-can-help/ai_eval_blog_image_one.png?v=2"></a></span><span class="title_aGrV">our input data set, including actual sentiment</span></div>
<p>The next step is to create another output table containing both the true measurement from our dataset and the value returned by our AI.
Since we can embed the Snowflake Cortex call directly in a SQL model we can easily build this in dbt using a simple reference function.</p>
<link href="/css/featherlight-styles.css" type="text/css" rel="stylesheet"><div class="
          docImage_EYbW
          
          
          
          
        " style="max-width:85%"><span><a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/ai-eval-in-dbt#" data-featherlight="/img/blog/2025-04-04-ai-evaluation-and-how-dbt-can-help/ai_eval_blog_image_two.png"><img data-toggle="lightbox" alt="results of our agentic workflow" title="results of our agentic workflow" src="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/img/blog/2025-04-04-ai-evaluation-and-how-dbt-can-help/ai_eval_blog_image_two.png?v=2"></a></span><span class="title_aGrV">results of our agentic workflow</span></div>
<p>We also include the input to our AI workflow along with the AI calculated and human determined measurement for the data set.
Including all these data points, while not strictly necessary, allows for clear understanding of what was fed into the AI workflow and easy traceability of specific responses.
We will follow this same pattern again, using a dbt reference function to create one last dbt model where we build the evaluation prompt and use Cortex Complete to give this prompt to Cortex and store the results.
The lionshare of the work building this model was the prompt engineering for the evaluation prompt. We initially built the prompt directly in Snowflake Cortex to ensure it was returning the type of response needed before moving the prompt into dbt.</p>
<link href="/css/featherlight-styles.css" type="text/css" rel="stylesheet"><div class="
          docImage_EYbW
          
          
          
          
        " style="max-width:85%"><span><a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/ai-eval-in-dbt#" data-featherlight="/img/blog/2025-04-04-ai-evaluation-and-how-dbt-can-help/ai_eval_blog_image_three.png"><img data-toggle="lightbox" alt="AI generated results automatically evaluated by one or more models" title="AI generated results automatically evaluated by one or more models" src="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/img/blog/2025-04-04-ai-evaluation-and-how-dbt-can-help/ai_eval_blog_image_three.png?v=2"></a></span><span class="title_aGrV">AI generated results automatically evaluated by one or more models</span></div>
<p>We chose to define our prompt as a Jinja variable as opposed to listing it directly in each dbt model.
This has the upside of increasing model readability, but obscures the text of what the prompt is from someone reading the model.
To address this issue and provide full traceability, we materialize the prompt as a column in this table. This means that each output row contains not only the evaluation score but also the exact prompt given to produce it.
Regardless of where you define your evaluation prompt, by including it as part of your dbt project it will benefit from the same change management and version control processes as the rest of your dbt project, ensuring strong governance of your AI workflows.
Another great benefit of this approach and the flexibility provided by dbt and Snowflake Cortex is that you can easily toggle the model you are using to run the evaluation. In this example we use Snowflake Llama, but using any other <a href="https://docs.snowflake.com/en/sql-reference/functions/complete-snowflake-cortex" target="_blank" rel="noopener noreferrer">supported model</a> is as easy as changing a function parameter.
You can even run multiple evaluations using different models to assess accuracy by simply adding additional columns to your dbt model.</p>
<link href="/css/featherlight-styles.css" type="text/css" rel="stylesheet"><div class="
          docImage_EYbW
          
          
          
          
        " style="max-width:85%"><span><a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/ai-eval-in-dbt#" data-featherlight="/img/blog/2025-04-04-ai-evaluation-and-how-dbt-can-help/ai_eval_blog_image_four.png"><img data-toggle="lightbox" alt="dbt Testing evaluates AI accuracry along side data quality" title="dbt Testing evaluates AI accuracry along side data quality" src="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/img/blog/2025-04-04-ai-evaluation-and-how-dbt-can-help/ai_eval_blog_image_four.png?v=2"></a></span><span class="title_aGrV">dbt Testing evaluates AI accuracry along side data quality</span></div>
<p>The final step here is writing a dbt <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/best-practices/writing-custom-generic-tests">custom test</a> to find any responses failing to meet our accuracy threshold. By creating this dbt test we can ensure issues with AI accuracy are caught and flagged as part of our standard dbt runs and quality checks.
We can also easily leverage dbt’s ability to <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/reference/resource-configs/store_failures">store test failures</a> to record quality issues found in AI processes for further investigation and triage.</p>
<p>As a final benefit of capturing AI evaluations as part of your dbt project is just that - your AI quality information becomes part of your dbt project meaning quality results are available in all the same ways as any other dbt test result.
You can view this information in <span>Catalog</span>, feed it into your data catalog of choice, use the test results to trigger additional downstream processes or visualize the information as quality dashboards through BI.
As AI workflows become more commonplace, businesses need a systematic way to evaluate and monitor AI outputs, just as they do with traditional data products. Fortunately, the same principles and tools within dbt can be easily applied to AI evaluation as well.
With dbt, data teams can bridge the gap between AI experimentation and AI in production, by ensuring trust, reliability, and governance to AI workflows.</p>
<p>Ready to bring AI evaluation into your dbt workflow? Get started with the dbt MCP server—it makes it easy to connect your AI systems to trusted, governed data.</p>]]></content>
        <author>
            <name>Kyle Dempsey</name>
        </author>
        <author>
            <name>Luis Leon</name>
        </author>
        <category label="analytics craft" term="analytics craft"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Scaling Data Pipelines for a Growth-Stage Fintech with Incremental Models]]></title>
        <id>https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/scaling-data-pipelines-fintech</id>
        <link href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/scaling-data-pipelines-fintech"/>
        <updated>2025-05-01T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[How Kuda leveraged dbt incremental models to reduce costs, speed up pipelines, and scale confidently.]]></summary>
        <content type="html"><![CDATA[<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="introduction">Introduction<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/scaling-data-pipelines-fintech#introduction" class="hash-link" aria-label="Direct link to Introduction" title="Direct link to Introduction">​</a></h2>
<p>Building scalable data pipelines in a fast-growing fintech can feel like fixing a bike while riding it. You must keep insights flowing even as data volumes explode. At Kuda (a Nigerian neo-bank), we faced this problem as our user base surged. Traditional batch ETL (rebuilding entire tables each run) started to buckle; pipelines took hours, and costs ballooned. We needed to keep data fresh without reprocessing everything. Our solution was to leverage dbt’s <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/docs/build/incremental-models">incremental models</a>, which process only new or changed records. This dramatically cut run times and curbed our BigQuery costs, letting us scale efficiently.</p>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="challenges-in-scaling">Challenges in Scaling<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/scaling-data-pipelines-fintech#challenges-in-scaling" class="hash-link" aria-label="Direct link to Challenges in Scaling" title="Direct link to Challenges in Scaling">​</a></h2>
<p>Rapid growth brought some serious scaling challenges, and the most important were:</p>
<ul>
<li>
<p><strong>Performance</strong>: Our nightly full-refresh models that once took minutes began taking hours as data grew. For example, our core transactions table became too slow to rebuild from scratch for each update. Analytics dashboards lagged, and stakeholders lost timely insights. In real-time fintech, such latency is unacceptable.</p>
</li>
<li>
<p><strong>Cost</strong>: More data and longer processing also drove up our BigQuery bills. Scanning a 2TB table every hour to grab a few MB of new data was wasteful. Under BigQuery’s on-demand pricing model, this could rack up thousands of dollars per month. We needed to increase throughput without scaling cost linearly, which meant rethinking our processing to avoid full table scans.</p>
</li>
<li>
<p><strong>Data</strong> Integrity: As pipelines and dependencies multiplied, so did the risk of inconsistencies or failures. Any new approach had to maintain accuracy and consistency even as we sped things up.</p>
</li>
</ul>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="approach-incremental-models--key-strategies">Approach: Incremental Models &amp; Key Strategies<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/scaling-data-pipelines-fintech#approach-incremental-models--key-strategies" class="hash-link" aria-label="Direct link to Approach: Incremental Models &amp; Key Strategies" title="Direct link to Approach: Incremental Models &amp; Key Strategies">​</a></h2>
<p>We tackled these issues by embracing dbt’s incremental models, which process only new or updated records since the last run. Instead of monolithic daily rebuilds, our models continuously ingested changes in small bites. Below, we outline our key <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/docs/build/incremental-strategy">incremental strategies</a> —<code>append</code>, <code>insert_overwrite</code>, and <code>merge</code> — and how we tuned performance and cost.</p>
<h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="append-strategy">Append Strategy<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/scaling-data-pipelines-fintech#append-strategy" class="hash-link" aria-label="Direct link to Append Strategy" title="Direct link to Append Strategy">​</a></h3>
<p>This is the simplest incremental approach: Each run adds new rows to the existing table and never touches old rows. It's ideal for append-only data (e.g. logs or transactions that never change after insertion).</p>
<p>In dbt, using append is straightforward. We configure the model as incremental and specify <code>incremental_strategy='append'</code> (supported in some adapters like Snowflake).</p>
<blockquote>
<p><strong>Note:</strong> <code>append</code> is not currently supported in BigQuery. Always confirm <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/docs/build/incremental-strategy#supported-incremental-strategies-by-adapter">adapter support</a> before choosing an incremental strategy.</p>
</blockquote>
<p>In the SQL, we filter the source to only new records since the last load. For example, to incrementally load new transactions:</p>
<h4 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="code-append-incremental-strategy">Code: Append Incremental Strategy<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/scaling-data-pipelines-fintech#code-append-incremental-strategy" class="hash-link" aria-label="Direct link to Code: Append Incremental Strategy" title="Direct link to Code: Append Incremental Strategy">​</a></h4>
<div class="language-jinja codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#d6deeb;--prism-background-color:#011627"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-jinja codeBlock_qGQc thin-scrollbar" style="color:#d6deeb;background-color:#011627"><code class="codeBlockLines_p187"><span class="token-line" style="color:#d6deeb"><span class="token plain">{{ config(</span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">    materialized = 'incremental',</span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">    incremental_strategy = 'append'</span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">) }}</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<div class="language-sql codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#d6deeb;--prism-background-color:#011627"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-sql codeBlock_qGQc thin-scrollbar" style="color:#d6deeb;background-color:#011627"><code class="codeBlockLines_p187"><span class="token-line" style="color:#d6deeb"><span class="token keyword" style="color:rgb(127, 219, 202)">SELECT</span><span class="token plain"> </span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">    transaction_id</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">    customer_id</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">    transaction_date</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">    amount</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">    </span><span class="token keyword" style="color:rgb(127, 219, 202)">status</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">FROM</span><span class="token plain"> {{ source</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(173, 219, 103)">'core'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">'transactions'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> }}</span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">{</span><span class="token operator" style="color:rgb(127, 219, 202)">%</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">if</span><span class="token plain"> is_incremental</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(127, 219, 202)">%</span><span class="token plain">}</span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">WHERE</span><span class="token plain"> transaction_date </span><span class="token operator" style="color:rgb(127, 219, 202)">&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">   </span><span class="token keyword" style="color:rgb(127, 219, 202)">SELECT</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">MAX</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">transaction_date</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">FROM</span><span class="token plain"> {{ this }}</span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">{</span><span class="token operator" style="color:rgb(127, 219, 202)">%</span><span class="token plain"> endif </span><span class="token operator" style="color:rgb(127, 219, 202)">%</span><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>This query appends only transactions that have a transaction date later than the maximum transaction date in the target table.</p>
<h4 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="append-incremental-model--before-incremental-run">Append Incremental Model – Before Incremental Run<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/scaling-data-pipelines-fintech#append-incremental-model--before-incremental-run" class="hash-link" aria-label="Direct link to Append Incremental Model – Before Incremental Run" title="Direct link to Append Incremental Model – Before Incremental Run">​</a></h4>
<div class="filterableTableContainer_mhtg"><table style="display:none"><thead><tr><th>transaction_id</th><th>customer_id</th><th>transaction_date</th><th>amount</th><th>status</th></tr></thead><tbody><tr><td>10001</td><td>C001</td><td>2023-09-28</td><td>₦12,000</td><td>completed</td></tr><tr><td>10002</td><td>C002</td><td>2023-09-28</td><td>₦5,000</td><td>completed</td></tr></tbody></table><div class="tableWrapper_oiMt"><div class="searchBar_xnmH"><div class="searchContainer_fLyJ"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M416 208c0 45.9-14.9 88.3-40 122.7L502.6 457.4c12.5 12.5 12.5 32.8 0 45.3s-32.8 12.5-45.3 0L330.7 376c-34.4 25.2-76.8 40-122.7 40C93.1 416 0 322.9 0 208S93.1 0 208 0S416 93.1 416 208zM208 352a144 144 0 1 0 0-288 144 144 0 1 0 0 288z"></path></svg><input type="text" placeholder="Search table..." class="searchInput_xT8h" aria-label="Search table" value=""></div></div><table class="filterableTable_QAKT"><thead><tr></tr></thead><tbody><tr><td colspan="5" style="text-align:center;padding:20px">Loading table...</td></tr></tbody></table></div></div>
<h4 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="append-incremental-model--after-incremental-run">Append Incremental Model – After Incremental Run<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/scaling-data-pipelines-fintech#append-incremental-model--after-incremental-run" class="hash-link" aria-label="Direct link to Append Incremental Model – After Incremental Run" title="Direct link to Append Incremental Model – After Incremental Run">​</a></h4>
<div class="filterableTableContainer_mhtg"><table style="display:none"><thead><tr><th>transaction_id</th><th>customer_id</th><th>transaction_date</th><th>amount</th><th>status</th></tr></thead><tbody><tr><td>10001</td><td>C001</td><td>2023-09-28</td><td>₦12,000</td><td>completed</td></tr><tr><td>10002</td><td>C002</td><td>2023-09-28</td><td>₦5,000</td><td>completed</td></tr><tr><td><strong>10003</strong></td><td><strong>C003</strong></td><td><strong>2023-09-29</strong></td><td><strong>₦8,500</strong></td><td><strong>completed</strong></td></tr><tr><td><strong>10004</strong></td><td><strong>C004</strong></td><td><strong>2023-09-30</strong></td><td><strong>₦7,250</strong></td><td><strong>completed</strong></td></tr><tr><td><strong>10005</strong></td><td><strong>C005</strong></td><td><strong>2023-09-30</strong></td><td><strong>₦3,100</strong></td><td><strong>pending</strong></td></tr></tbody></table><div class="tableWrapper_oiMt"><div class="searchBar_xnmH"><div class="searchContainer_fLyJ"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M416 208c0 45.9-14.9 88.3-40 122.7L502.6 457.4c12.5 12.5 12.5 32.8 0 45.3s-32.8 12.5-45.3 0L330.7 376c-34.4 25.2-76.8 40-122.7 40C93.1 416 0 322.9 0 208S93.1 0 208 0S416 93.1 416 208zM208 352a144 144 0 1 0 0-288 144 144 0 1 0 0 288z"></path></svg><input type="text" placeholder="Search table..." class="searchInput_xT8h" aria-label="Search table" value=""></div></div><table class="filterableTable_QAKT"><thead><tr></tr></thead><tbody><tr><td colspan="5" style="text-align:center;padding:20px">Loading table...</td></tr></tbody></table></div></div>
<p><strong><em>Illustration: The "Before" table shows data before an incremental run; the "After" table shows new transactions (in bold) added. No historical data is touched. Append is great for immutable data streams (like transaction logs or event streams that only ever grow).</em></strong></p>
<p>Append served us well for ingestion pipelines that just accumulate history without reprocessing old data. However, we had to guard against duplicates (if the source might resend records, we applied deduplication or unique constraints). Also, pure append doesn’t handle updates or deletions to existing records. If data can change after insertion (e.g. a transaction status moves from "pending" to "completed"), a different strategy is needed.</p>
<h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="insert-overwrite-strategy">Insert Overwrite Strategy<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/scaling-data-pipelines-fintech#insert-overwrite-strategy" class="hash-link" aria-label="Direct link to Insert Overwrite Strategy" title="Direct link to Insert Overwrite Strategy">​</a></h3>
<p>For data partitioned by date (or another key) that may need partial replacements, <code>insert_overwrite</code> is ideal. Instead of merging rows, this strategy overwrites entire partitions of the target table each run. The table must be partitioned (daily, hourly, etc.), and the model will drop and rebuild only the partitions that have new or updated data.</p>
<p>We used <code>insert_overwrite</code> for partitioned data like daily aggregates, where changes are isolated by date. For example, if a table is partitioned by <code>transaction_date</code>, an <code>insert_overwrite</code> model can refresh just the partition for <em>"2023-10-01"</em> without affecting other days.</p>
<p>Here’s how we configured a model to use <code>insert_overwrite</code> on BigQuery:</p>
<h4 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="code-insert-overwrite-strategy">Code: Insert Overwrite Strategy<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/scaling-data-pipelines-fintech#code-insert-overwrite-strategy" class="hash-link" aria-label="Direct link to Code: Insert Overwrite Strategy" title="Direct link to Code: Insert Overwrite Strategy">​</a></h4>
<div class="language-jinja codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#d6deeb;--prism-background-color:#011627"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-jinja codeBlock_qGQc thin-scrollbar" style="color:#d6deeb;background-color:#011627"><code class="codeBlockLines_p187"><span class="token-line" style="color:#d6deeb"><span class="token plain">{{ config(</span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">    materialized = 'incremental',</span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">    incremental_strategy = 'insert_overwrite',</span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">    partition_by = { 'field': 'transaction_date', 'data_type': 'date' }</span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">) }}</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<div class="language-sql codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#d6deeb;--prism-background-color:#011627"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-sql codeBlock_qGQc thin-scrollbar" style="color:#d6deeb;background-color:#011627"><code class="codeBlockLines_p187"><span class="token-line" style="color:#d6deeb"><span class="token keyword" style="color:rgb(127, 219, 202)">SELECT</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">    customer_id</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">    transaction_date</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">    amount</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">    transaction_type</span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">FROM</span><span class="token plain"> {{ source</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(173, 219, 103)">'core'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">'transactions'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> }}</span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">WHERE</span><span class="token plain"> transaction_date </span><span class="token operator" style="color:rgb(127, 219, 202)">&gt;=</span><span class="token plain"> {{ this</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">last_partition }}</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Here, <code>partition_by</code> defines the table partition. The <code>WHERE</code> clause uses <code>{{ this.last_partition }}</code> (<em>the latest partition already present in the target</em>) to pull only data for new or updated partitions. On each run, BigQuery will replace any existing partition that meets the filter (e.g. the partition for the latest date) with the query results. Older partitions stay untouched.</p>
<h4 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="insert-overwrite-strategy--before-incremental-run">Insert Overwrite Strategy – Before Incremental Run<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/scaling-data-pipelines-fintech#insert-overwrite-strategy--before-incremental-run" class="hash-link" aria-label="Direct link to Insert Overwrite Strategy – Before Incremental Run" title="Direct link to Insert Overwrite Strategy – Before Incremental Run">​</a></h4>
<div class="filterableTableContainer_mhtg"><table style="display:none"><thead><tr><th>transaction_date</th><th>transaction_id</th><th>customer_id</th><th>amount</th><th>status</th></tr></thead><tbody><tr><td>2023-09-29</td><td>11001</td><td>C011</td><td>₦14,000</td><td>completed</td></tr><tr><td>2023-09-29</td><td>11002</td><td>C012</td><td>₦6,500</td><td>completed</td></tr><tr><td><strong>2023-10-01</strong></td><td><strong>12001</strong></td><td><strong>C021</strong></td><td><strong>₦8,000</strong></td><td><strong>pending</strong></td></tr><tr><td><strong>2023-10-01</strong></td><td><strong>12002</strong></td><td><strong>C022</strong></td><td><strong>₦4,200</strong></td><td><strong>completed</strong></td></tr></tbody></table><div class="tableWrapper_oiMt"><div class="searchBar_xnmH"><div class="searchContainer_fLyJ"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M416 208c0 45.9-14.9 88.3-40 122.7L502.6 457.4c12.5 12.5 12.5 32.8 0 45.3s-32.8 12.5-45.3 0L330.7 376c-34.4 25.2-76.8 40-122.7 40C93.1 416 0 322.9 0 208S93.1 0 208 0S416 93.1 416 208zM208 352a144 144 0 1 0 0-288 144 144 0 1 0 0 288z"></path></svg><input type="text" placeholder="Search table..." class="searchInput_xT8h" aria-label="Search table" value=""></div></div><table class="filterableTable_QAKT"><thead><tr></tr></thead><tbody><tr><td colspan="5" style="text-align:center;padding:20px">Loading table...</td></tr></tbody></table></div></div>
<p><em>(Partition to be overwritten highlighted in bold.)</em></p>
<h4 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="insert-overwrite-strategy--after-incremental-run">Insert Overwrite Strategy – After Incremental Run<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/scaling-data-pipelines-fintech#insert-overwrite-strategy--after-incremental-run" class="hash-link" aria-label="Direct link to Insert Overwrite Strategy – After Incremental Run" title="Direct link to Insert Overwrite Strategy – After Incremental Run">​</a></h4>
<div class="filterableTableContainer_mhtg"><table style="display:none"><thead><tr><th>transaction_date</th><th>transaction_id</th><th>customer_id</th><th>amount</th><th>status</th></tr></thead><tbody><tr><td>2023-09-29</td><td>11001</td><td>C011</td><td>₦14,000</td><td>completed</td></tr><tr><td>2023-09-29</td><td>11002</td><td>C012</td><td>₦6,500</td><td>completed</td></tr><tr><td><strong>2023-10-01</strong></td><td><strong>12003</strong></td><td><strong>C023</strong></td><td><strong>₦8,150</strong></td><td><strong>completed</strong></td></tr><tr><td><strong>2023-10-01</strong></td><td><strong>12004</strong></td><td><strong>C024</strong></td><td><strong>₦3,900</strong></td><td><strong>completed</strong></td></tr><tr><td><strong>2023-10-01</strong></td><td><strong>12005</strong></td><td><strong>C025</strong></td><td><strong>₦5,500</strong></td><td><strong>completed</strong></td></tr></tbody></table><div class="tableWrapper_oiMt"><div class="searchBar_xnmH"><div class="searchContainer_fLyJ"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M416 208c0 45.9-14.9 88.3-40 122.7L502.6 457.4c12.5 12.5 12.5 32.8 0 45.3s-32.8 12.5-45.3 0L330.7 376c-34.4 25.2-76.8 40-122.7 40C93.1 416 0 322.9 0 208S93.1 0 208 0S416 93.1 416 208zM208 352a144 144 0 1 0 0-288 144 144 0 1 0 0 288z"></path></svg><input type="text" placeholder="Search table..." class="searchInput_xT8h" aria-label="Search table" value=""></div></div><table class="filterableTable_QAKT"><thead><tr></tr></thead><tbody><tr><td colspan="5" style="text-align:center;padding:20px">Loading table...</td></tr></tbody></table></div></div>
<p><em>(New partition data is shown in bold, replacing the old partition.)</em></p>
<p><em><strong><em>Illustration: "Before" shows a partitioned table with the October 1, 2023 partition highlighted; "After" shows that partition replaced with fresh rows. This approach lets us refresh a specific day’s data (e.g. to capture late-arriving transactions or corrections) without rebuilding the whole table.</em></strong></em></p>
<p>At Kuda, <code>insert_overwrite</code> was invaluable for derived tables and rollups. For instance, our daily customer spend aggregates are updated incrementally by replacing just the latest day's data, keeping those tables accurate with minimal cost. By replacing whole partitions, we avoided complex row-by-row merges while still catching any corrections within that day (for example, a back-dated transaction on that day would be picked up when the partition is reprocessed).</p>
<p>One note on static vs dynamic partitions: We mostly used static daily partitions (overwriting entire days). Some warehouses (and newer dbt features) allow dynamic partition updates (updating only changed rows within a partition), but we stuck to whole-day replacements for simplicity. It's easier to say "<em>each run rebuilds yesterday’s partition from scratch,</em>" ensuring we capture any late modifications for that day. This dramatically improved performance for large tables (no full table scans) while still correcting recent data when needed. We just had to align the partition_by field and filter logic to avoid wiping the wrong partition.</p>
<h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="merge-strategy">Merge Strategy<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/scaling-data-pipelines-fintech#merge-strategy" class="hash-link" aria-label="Direct link to Merge Strategy" title="Direct link to Merge Strategy">​</a></h3>
<p>For tables where new records arrive and existing ones can change, we used the merge strategy. It performs an upsert based on a unique key: new rows are inserted, and if a key already exists, specified fields are updated. This is perfect for data like customer profiles or account balances that evolve.</p>
<p>In dbt, using <code>incremental_strategy='merge'</code> requires a unique_key (on BigQuery or Snowflake, dbt compiles it into a merge statement). We can also limit which columns get updated using merge_update_columns or exclude certain fields with <code>merge_exclude_columns</code>. For example:</p>
<h4 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="code-merge-strategy">Code: Merge Strategy<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/scaling-data-pipelines-fintech#code-merge-strategy" class="hash-link" aria-label="Direct link to Code: Merge Strategy" title="Direct link to Code: Merge Strategy">​</a></h4>
<div class="language-jinja codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#d6deeb;--prism-background-color:#011627"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-jinja codeBlock_qGQc thin-scrollbar" style="color:#d6deeb;background-color:#011627"><code class="codeBlockLines_p187"><span class="token-line" style="color:#d6deeb"><span class="token plain">{{ config(</span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">    materialized = 'incremental',</span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">    incremental_strategy = 'merge',</span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">    unique_key = 'account_id',</span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">    merge_update_columns = ['balance', 'last_updated']</span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">) }}</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<div class="language-sql codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#d6deeb;--prism-background-color:#011627"><div class="codeBlockContent_m3Ux"><pre tabindex="0" class="prism-code language-sql codeBlock_qGQc thin-scrollbar" style="color:#d6deeb;background-color:#011627"><code class="codeBlockLines_p187"><span class="token-line" style="color:#d6deeb"><span class="token keyword" style="color:rgb(127, 219, 202)">SELECT</span><span class="token plain"> </span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">    account_id</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">    balance</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">    last_updated</span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">FROM</span><span class="token plain"> {{ source</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(173, 219, 103)">'core'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">'accounts'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> }}</span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">{</span><span class="token operator" style="color:rgb(127, 219, 202)">%</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">if</span><span class="token plain"> is_incremental</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(127, 219, 202)">%</span><span class="token plain">}</span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">WHERE</span><span class="token plain"> last_updated </span><span class="token operator" style="color:rgb(127, 219, 202)">&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">   </span><span class="token keyword" style="color:rgb(127, 219, 202)">SELECT</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">MAX</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">last_updated</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">FROM</span><span class="token plain"> {{ this }}</span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#d6deeb"><span class="token plain">{</span><span class="token operator" style="color:rgb(127, 219, 202)">%</span><span class="token plain"> endif </span><span class="token operator" style="color:rgb(127, 219, 202)">%</span><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup_6DOT"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>This model selects only new or updated records (those with a <code>last_updated</code> more recent than the max in the target) and merges them into the accounts table on <code>account_id</code>. We chose to update only the <code>balance</code> and <code>last_updated</code> fields for existing accounts (to avoid overwriting other data). If an incoming <code>account_id</code> doesn’t exist in the target yet, a new row is inserted.</p>
<p>Merge was our go-to for upserts. For example, we maintained a daily updated accounts table of customer statuses and balances using merge. Each day, new accounts were added, and any changes (balance updates, status changes) were merged into existing records. This prevented duplicates (which a naive append would create) and ensured one row per account with the latest info.</p>
<p>We learned to define unique keys and update columns carefully. In one case, we omitted a merge_exclude_columns and accidentally overwrote a timestamp we meant to preserve—a quick lesson in being explicit. Also, merge comes with a performance cost: each run joins the new data with the existing table. With proper clustering on the key and only a day’s worth of new data, this was fine for us, but at a very large scale, it needs monitoring.</p>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="optimizing-performance-and-cost">Optimizing Performance and Cost<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/scaling-data-pipelines-fintech#optimizing-performance-and-cost" class="hash-link" aria-label="Direct link to Optimizing Performance and Cost" title="Direct link to Optimizing Performance and Cost">​</a></h2>
<p>Choosing the right incremental strategy was half the battle; we also employed several performance tuning and cost optimization techniques to make our pipelines truly scale:</p>
<ul>
<li>
<p><strong>Partitioning</strong>: On large tables, we partitioned by date (or another key) so incremental runs only scan the new slice. For example, partitioning the transactions table by transaction_date meant a daily incremental load only touched that day's partition. BigQuery’s partition pruning reduced scans from entire multi-terabyte tables to just a few GB per run (e.g. 2TB down to 0.01TB), yielding huge savings. Partitioning also sped up downstream queries that filter by date.</p>
</li>
<li>
<p><strong>Clustering</strong>: We added clustering on columns frequently used in filters or joins (e.g. clustering transactions by <code>customer_id</code>). In BigQuery, clustering sorts the data by those columns, so queries filtering on them scan less data within each partition. The improvements were subtle but meaningful; some queries that once scanned tens of GBs now scan only a fraction when the table is well-clustered.</p>
</li>
<li>
<p><strong>Smart Scheduling</strong>: We tuned model run frequencies to balance freshness vs. cost. Not every model needs to run constantly. Our customer-facing tables (transactions, balances) ran hourly for near-real-time updates, whereas internal analytics models ran daily or a few times per day. Adjusting schedules avoided wasteful runs and saved on compute cost. We also used dependency-based scheduling (via dbt Cloud), so heavy models ran only after upstream data was updated, preventing runs when no new source data arrived.</p>
</li>
<li>
<p><strong>Warehouse Tuning</strong>: We optimized our warehouse compute as well. Since incremental models drastically cut per-run processing, we could use smaller clusters/slots and run more often without overspending, a big win as data volumes grew.</p>
</li>
<li>
<p><strong>Monitoring &amp; Alerting</strong>: We tracked metrics like run durations and rows processed to catch anomalies. For example, if a daily incremental model that usually adds hundreds of rows suddenly adds zero, that's a red flag (upstream failure or missing source data). Similarly, if a job that normally takes 5 minutes jumps to 50, it likely did an unintended full scan. We also watched data freshness, if an hourly model hasn’t loaded new data in 3 hours, we investigate. These checks helped us catch issues early (like a stale source or a broken filter) and kept data flowing reliably.</p>
</li>
</ul>
<p>With these optimizations in place, we vastly improved our pipeline speed and cost-efficiency. Instead of fearing the next data surge, we were confident our system could handle growth by design.</p>
<h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="real-world-implementation-kuda-case-study">Real-World Implementation: Kuda Case Study<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/scaling-data-pipelines-fintech#real-world-implementation-kuda-case-study" class="hash-link" aria-label="Direct link to Real-World Implementation: Kuda Case Study" title="Direct link to Real-World Implementation: Kuda Case Study">​</a></h3>
<p>How did these approaches work out in practice at Kuda during hyper-growth?</p>
<p>One critical dataset was our customer transactions feed. Initially, a full daily rebuild of the transactions table took over an hour and scanned the entire history. We refactored it into an incremental model (append strategy with partition pruning). The first run built the historical backlog, and subsequent runs pulled only new transactions. The difference was night and day: the incremental job ran in minutes, and data scanned per run dropped by over 90%. Analysts saw new transactions within the hour, and our monthly BigQuery cost for that table plummeted even as data continued to grow.</p>
<p>To illustrate, here’s a simplified daily transactions summary. Initially, it contained data up to <em>Sept 30, 2023</em>:</p>
<h4 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="daily-transactions-summary--before">Daily Transactions Summary – Before<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/scaling-data-pipelines-fintech#daily-transactions-summary--before" class="hash-link" aria-label="Direct link to Daily Transactions Summary – Before" title="Direct link to Daily Transactions Summary – Before">​</a></h4>
<div class="filterableTableContainer_mhtg"><table style="display:none"><thead><tr><th>date</th><th>transactions_count</th><th>total_amount</th></tr></thead><tbody><tr><td>2023-09-28</td><td>1,045</td><td>25,100,000</td></tr><tr><td>2023-09-29</td><td>980</td><td>22,340,000</td></tr><tr><td>2023-09-30</td><td>1,102</td><td>27,500,000</td></tr></tbody></table><div class="tableWrapper_oiMt"><div class="searchBar_xnmH"><div class="searchContainer_fLyJ"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M416 208c0 45.9-14.9 88.3-40 122.7L502.6 457.4c12.5 12.5 12.5 32.8 0 45.3s-32.8 12.5-45.3 0L330.7 376c-34.4 25.2-76.8 40-122.7 40C93.1 416 0 322.9 0 208S93.1 0 208 0S416 93.1 416 208zM208 352a144 144 0 1 0 0-288 144 144 0 1 0 0 288z"></path></svg><input type="text" placeholder="Search table..." class="searchInput_xT8h" aria-label="Search table" value=""></div></div><table class="filterableTable_QAKT"><thead><tr></tr></thead><tbody><tr><td colspan="5" style="text-align:center;padding:20px">Loading table...</td></tr></tbody></table></div></div>
<p>After the next incremental load (bringing in transactions from <em>October 1, 2023</em>), the table automatically includes the new day's metrics without recomputing prior days:</p>
<h4 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="daily-transactions-summary--after">Daily Transactions Summary – After<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/scaling-data-pipelines-fintech#daily-transactions-summary--after" class="hash-link" aria-label="Direct link to Daily Transactions Summary – After" title="Direct link to Daily Transactions Summary – After">​</a></h4>
<div class="filterableTableContainer_mhtg"><table style="display:none"><thead><tr><th>date</th><th>transactions_count</th><th>total_amount</th></tr></thead><tbody><tr><td>2023-09-28</td><td>1,045</td><td>25,100,000</td></tr><tr><td>2023-09-29</td><td>980</td><td>22,340,000</td></tr><tr><td>2023-09-30</td><td>1,102</td><td>27,500,000</td></tr><tr><td>2023-10-01</td><td>1,210</td><td>30,230,000</td></tr></tbody></table><div class="tableWrapper_oiMt"><div class="searchBar_xnmH"><div class="searchContainer_fLyJ"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M416 208c0 45.9-14.9 88.3-40 122.7L502.6 457.4c12.5 12.5 12.5 32.8 0 45.3s-32.8 12.5-45.3 0L330.7 376c-34.4 25.2-76.8 40-122.7 40C93.1 416 0 322.9 0 208S93.1 0 208 0S416 93.1 416 208zM208 352a144 144 0 1 0 0-288 144 144 0 1 0 0 288z"></path></svg><input type="text" placeholder="Search table..." class="searchInput_xT8h" aria-label="Search table" value=""></div></div><table class="filterableTable_QAKT"><thead><tr></tr></thead><tbody><tr><td colspan="5" style="text-align:center;padding:20px">Loading table...</td></tr></tbody></table></div></div>
<p><em><strong><em>Table: Example of a daily transactions summary. After an incremental load for 2023-10-01, the new day’s data appears without reprocessing previous days.</em></strong></em></p>
<p>This approach kept our teams and customers up-to-date. Customer support could view nearly real-time transactions to investigate issues, and customers could generate current account statements on the fly.</p>
<p>We also used incremental models for regulatory and finance reporting. For example, our Finance team needed a daily reconciliation of balances and an end-of-day accounts table. They were fine with data being a day old, but it had to be accurate and deduplicated. We built this with a nightly incremental merge on the accounts table, merging changes from the core accounts data into a fresh daily view of account states. It provided a reliable daily snapshot of accounts. (Our Finance team didn’t realize any fancy incremental process was involved, they just got their report each morning!)</p>
<p>During the launch of a new card product, we needed to monitor transaction declines and errors in near real-time. Our existing daily-refreshed dashboard wasn’t enough. We set up an incremental model that ingested card transaction events every 15 minutes. To ensure that no historical fixes were missed, we also scheduled a nightly full refresh of this model during the launch period. This hybrid approach gave us timely visibility and a daily catch-up for any late-arriving corrections. It proved crucial: we spotted issues (like a spike in declines from an API glitch) early and fixed them, minimizing customer impact. After the launch, we reverted to purely incremental runs once things stabilized.</p>
<p>The overall impact at Kuda was huge. Some heavy transformations that were close to failing became reliable again. Stakeholders noticed fresher data in their reports, our customer satisfaction scores improved as no one saw stale data. By controlling costs and keeping pipelines efficient, we kept management and regulators happy.</p>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="lessons-learned--best-practices">Lessons Learned &amp; Best Practices<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/scaling-data-pipelines-fintech#lessons-learned--best-practices" class="hash-link" aria-label="Direct link to Lessons Learned &amp; Best Practices" title="Direct link to Lessons Learned &amp; Best Practices">​</a></h2>
<p>Throughout this scaling journey, we learned a ton about what worked and what didn’t. Here are some of the key lessons and best practices we’d recommend to any growth-stage fintech looking to implement incremental models:</p>
<ul>
<li>
<p><strong>Choose the Right Strategy</strong>: Not all tables should use the same incremental approach. Generally, use append for insert-only data, <code>insert_overwrite</code> for data partitioned by date (or ID) where you can replace whole chunks, and merge for true upsert scenarios. If source deletes are an issue, consider <code>delete+insert</code> or handle soft deletes.</p>
</li>
<li>
<p><strong>Partition Wisely</strong>: Partitioning is critical, but pick an appropriate granularity. The right grain (hour, day, month) depends on data volume and query patterns. For us, daily partitions were often the sweet spot, small enough to reduce scanned data, not so small as to create thousands of partitions. Always align your incremental filter with the partition field to enable pruning.</p>
</li>
<li>
<p><strong>Monitor Your Models</strong>: Implement tests or alerts on incremental models. For example, check that each run’s row count is within expected bounds, if a daily incremental that usually adds hundreds of rows suddenly adds zero, that’s a red flag. Catching these issues early prevents bigger problems down the line.</p>
</li>
<li>
<p><strong>Periodic Full Refreshes</strong>: Over time, even a well-built incremental model can drift due to small errors or schema changes. We scheduled occasional full refreshes for critical models to realign them with source data, essentially giving a clean slate that catches any discrepancies or missed data. Similarly, after major logic changes, we’d do a one-time full refresh to apply the new logic across all historical data and then switch back to incremental.</p>
</li>
<li>
<p><strong>Test and Document</strong>: We treated incremental models like mission-critical code. We wrote tests to ensure the logic is sound (for instance, after an incremental run, the target’s record count for a period equals the source’s count for that period, if not, the filter might be wrong). We also documented each model’s assumptions (e.g. “<em>this model runs incrementally, do not disable the is_incremental filter in development</em>”). Good documentation helped new team members avoid breaking incremental logic.</p>
</li>
<li>
<p><strong>Design for Scale Early</strong>: Our biggest lesson was to plan for scale from the start. Now, when designing a new model or pipeline, we ask, “<em>What if the data grows 10x?</em>”. If a full refresh won't be feasible at that size, we build it incrementally from day one. It's much easier than refactoring under pressure later. This mindset, combined with dbt’s flexible incremental features, has future-proofed our pipelines. As our data continues to grow, the incremental approach should keep holding up.</p>
</li>
</ul>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="conclusion">Conclusion<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/scaling-data-pipelines-fintech#conclusion" class="hash-link" aria-label="Direct link to Conclusion" title="Direct link to Conclusion">​</a></h2>
<p>Scaling a fintech data platform doesn’t have to mean scaling cost and runtime at the same pace. By using dbt’s incremental models—paired with optimizations like partitioning, clustering, and careful scheduling—Kuda transformed its pipelines to handle rapid growth. We kept data fresh and accurate for users without breaking the bank. Incremental processing let us handle ever-increasing volumes in bite-sized chunks, maintaining agility as the company grew.</p>
<p>If you’re at a growing company struggling with slow or expensive data jobs, give dbt’s incremental models a try. As we saw at Kuda, the payoff can be huge: faster insights, happier stakeholders, and a data platform ready for whatever the future brings. The future of data processing (in fintech and beyond) is incremental. With tools like dbt, you can ride the wave of growth instead of drowning in it.</p>]]></content>
        <author>
            <name>Adedamola Onabanjo</name>
        </author>
        <category label="analytics" term="analytics"/>
        <category label="dbt Cloud" term="dbt Cloud"/>
        <category label="fintech" term="fintech"/>
        <category label="BigQuery" term="BigQuery"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Introducing the dbt MCP Server – Bringing Structured Data to AI Workflows and Agents]]></title>
        <id>https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/introducing-dbt-mcp-server</id>
        <link href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/introducing-dbt-mcp-server"/>
        <updated>2025-04-21T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[We’re open‑sourcing an experimental dbt MCP server so LLMs and agents can discover, query, and run your dbt project.]]></summary>
        <content type="html"><![CDATA[<p>dbt is the standard for creating governed, trustworthy datasets on top of your structured data. <a href="https://www.anthropic.com/news/model-context-protocol" target="_blank" rel="noopener noreferrer">MCP</a> is showing increasing promise as the standard for providing context to LLMs to allow them to function at a high level in real world, operational scenarios.</p>
<p>Today, we are open sourcing an experimental version of the <a href="https://github.com/dbt-labs/dbt-mcp/tree/main" target="_blank" rel="noopener noreferrer">dbt MCP server</a>. We expect that over the coming years, structured data is going to become heavily integrated into AI workflows and that dbt will play a key role in building and provisioning this data.</p>
<p>In particular, we expect both <a href="https://roundup.getdbt.com/p/how-ai-will-disrupt-bi-as-we-know" target="_blank" rel="noopener noreferrer">Business Intelligence</a> and <a href="https://roundup.getdbt.com/p/how-ai-will-disrupt-data-engineering" target="_blank" rel="noopener noreferrer">Data Engineering</a> will be driven by AI operating on top of the context defined in your dbt projects.</p>
<p><strong>We are committed to building the data control plane that enables AI to reliably access structured data from across your entire data lineage.</strong> Over the coming months and years, data teams will increasingly focus on building the rich context that feeds into the dbt MCP server.  Both AI agents and business stakeholders will then operate on top of LLM-driven systems hydrated by the dbt MCP context.</p>
<div style="margin:40px 10px"><div class="loomWrapper_TTvb"><iframe width="640" class="loomFrame_B61a" height="400" src="https://www.loom.com/embed/28cd33da8bcc41ccbe43338d327e73d8" frameborder="0" allowfullscreen="" webkitallowfullscreen="true" mozallowfullscreen="true"></iframe></div></div>
<p>Today’s system is not a full realization of the vision in the posts shared above, but it is a meaningful step towards safely integrating your structured enterprise data into AI workflows. In this post, we’ll walk through what the dbt MCP server can do today, some tips for getting started and some of the limitations of the current implementation.</p>
<p>We believe it is important for the industry to start coalescing on best practices for safe and trustworthy ways to access your business data via LLM.</p>
<p><strong>What is MCP?</strong></p>
<p>MCP stands for Model Context Protocol - it is an open protocol released by Anthropic in <a href="https://www.anthropic.com/news/model-context-protocol" target="_blank" rel="noopener noreferrer">November of last year</a> to allow AI systems to dynamically pull in context and data. Why does this matter?</p>
<blockquote>
<p>Even the most sophisticated models are constrained by their isolation from data—trapped behind information silos and legacy systems. Every new data source requires its own custom implementation, making truly connected systems difficult to scale.</p>
<p>MCP addresses this challenge. It provides a universal, open standard for connecting AI systems with data sources, replacing fragmented integrations with a single protocol. - Anthropic</p>
</blockquote>
<p>Since then, MCP has become widely supported, with Google, Microsoft and OpenAI all committing to support MCP.</p>
<p><strong>What does the dbt MCP Server do?</strong></p>
<p>Think of it as the missing glue between:</p>
<ul>
<li><strong>Your dbt project</strong> (models, docs, lineage, Semantic&nbsp;Layer)</li>
<li><strong>Any MCP‑enabled <a href="https://modelcontextprotocol.io/clients" target="_blank" rel="noopener noreferrer">client</a></strong> (Claude Desktop Projects, Cursor, agent frameworks, custom apps, etc.)</li>
</ul>
<p>We’ve <a href="https://roundup.getdbt.com/p/semantic-layer-as-the-data-interface" target="_blank" rel="noopener noreferrer">known for a while</a> that the combination of structured data from your dbt project + LLMs is a potent combo (particularly when using the dbt Semantic Layer). The question has been, what is the best way to provision this across a wide variety of LLM applications in a way that puts the power in the hands of the Community and the ecosystem, rather than us building out a series of one-off integrations.</p>
<p>The dbt MCP server provides access to a set of <em>tools</em> that operate on top of your dbt project. These tools can be called by LLM systems to learn about your data and metadata.</p>
<p><strong>Remember, as with any AI workflows, to make sure that you are taking appropriate caution in terms of giving these access to production systems and data. Consider starting in a sandbox environment or only granting read permissions.</strong></p>
<p>There are three primary functions of the dbt MCP server today.</p>
<link href="/css/featherlight-styles.css" type="text/css" rel="stylesheet"><div class="
          docImage_EYbW
          
          
          
          
        " style="max-width:100%"><span><a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/introducing-dbt-mcp-server#" data-featherlight="/img/blog/2025-04-18-dbt-mcp-server/mcp_use_cases.png"><img data-toggle="lightbox" alt="Three use‑case pillars of the dbt MCP server" title="Three use‑case pillars of the dbt MCP server" src="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/img/blog/2025-04-18-dbt-mcp-server/mcp_use_cases.png?v=2"></a></span><span class="title_aGrV">Three use‑case pillars of the dbt MCP server</span></div>
<ul>
<li>Data discovery: Understand what data assets exist in your dbt project.</li>
<li>Data querying: Directly query the data in your dbt project. This has two components:<!-- -->
<ul>
<li>Use the dbt Semantic Layer for trustworthy, single source of truth reporting on your metrics</li>
<li>Execution of SQL queries for more freewheeling data exploration and development</li>
</ul>
</li>
<li>Run and perform commands within dbt: Access the dbt CLI to run a project and perform other operations</li>
</ul>
<link href="/css/featherlight-styles.css" type="text/css" rel="stylesheet"><div class="
          docImage_EYbW
          
          
          
          
        " style="max-width:100%"><span><a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/introducing-dbt-mcp-server#" data-featherlight="/img/blog/2025-04-18-dbt-mcp-server/mcp_architecture_overview.png"><img data-toggle="lightbox" alt="How the dbt MCP server fits between data sources and MCP‑enabled clients" title="How the dbt MCP server fits between data sources and MCP‑enabled clients" src="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/img/blog/2025-04-18-dbt-mcp-server/mcp_architecture_overview.png?v=2"></a></span><span class="title_aGrV">How the dbt MCP server fits between data sources and MCP‑enabled clients</span></div>
<p>❓Do I need to be a dbt Cloud customer to use the dbt MCP server?</p>
<ul>
<li>No - there is functionality for both <span>dbt</span> and dbt Core users included in the MCP. Over time, Cloud-specific services will be built into the MCP server where they provide differentiated value.</li>
</ul>
<p>Let’s walk through examples of these and why each of them can be helpful in human driven and agent driven use cases:</p>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="using-the-dbt-mcp-server-for-data-asset-discovery"><strong>Using the dbt MCP Server for Data Asset Discovery</strong><a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/introducing-dbt-mcp-server#using-the-dbt-mcp-server-for-data-asset-discovery" class="hash-link" aria-label="Direct link to using-the-dbt-mcp-server-for-data-asset-discovery" title="Direct link to using-the-dbt-mcp-server-for-data-asset-discovery">​</a></h2>
<p>dbt has knowledge about the data assets that exist across your entire data stack, from raw staging models to polished analytical marts. The dbt MCP server exposes this knowledge in a way that makes it accessible to LLMs and AI agents, enabling powerful discovery capabilities:</p>
<ul>
<li><strong>For human stakeholders</strong>: Learn about your production dbt project interactively through natural language. Business users can ask questions like "What customer data do we have?" or "Where do we store marketing spend information?" and receive accurate information based on your dbt project's documentation and structure.</li>
<li><strong>For AI agent workflows</strong>: Automatically discover and understand the available data models, their relationships, and their structures without human intervention. This allows agents to autonomously navigate complex data environments and produce accurate insights. This can be useful context for any agent that needs to operate on top of information in a data platform.</li>
</ul>
<p>The data discovery tools allow LLMs to understand what data exists, how it's structured, and how different data assets relate to each other. This contextual understanding is essential for generating accurate SQL, answering business questions, and providing trustworthy data insights.</p>
<h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="data-asset-discovery-tools"><strong>Data Asset Discovery Tools:</strong><a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/introducing-dbt-mcp-server#data-asset-discovery-tools" class="hash-link" aria-label="Direct link to data-asset-discovery-tools" title="Direct link to data-asset-discovery-tools">​</a></h3>
<p><em>note - for all of these tools, you do not need to directly access them in your workflow. Rather, the MCP client will use the context you have provided to determine which is the most accurate tool to use at a given time.</em></p>
<div class="filterableTableContainer_mhtg"><table style="display:none"><thead><tr><th>Tool Name</th><th>Purpose</th><th>Output</th></tr></thead><tbody><tr><td><code>get_all_models</code></td><td>Provides a complete inventory of all models in the dbt project, regardless of type</td><td>List of all model names and their descriptions</td></tr><tr><td><code>get_mart_models</code></td><td>Identifies presentation layer models specifically designed for end-user consumption</td><td>List of mart model names and descriptions (models in the reporting layer)</td></tr><tr><td><code>get_model_details</code></td><td>Retrieves comprehensive information about a specific model</td><td>Compiled SQL, description, column names, column descriptions, and column data types</td></tr><tr><td><code>get_model_parents</code></td><td>Identifies upstream dependencies for a specific model</td><td>List of parent models that the specified model depends on</td></tr></tbody></table><div class="tableWrapper_oiMt"><div class="searchBar_xnmH"><div class="searchContainer_fLyJ"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M416 208c0 45.9-14.9 88.3-40 122.7L502.6 457.4c12.5 12.5 12.5 32.8 0 45.3s-32.8 12.5-45.3 0L330.7 376c-34.4 25.2-76.8 40-122.7 40C93.1 416 0 322.9 0 208S93.1 0 208 0S416 93.1 416 208zM208 352a144 144 0 1 0 0-288 144 144 0 1 0 0 288z"></path></svg><input type="text" placeholder="Search table..." class="searchInput_xT8h" aria-label="Search table" value=""></div></div><table class="filterableTable_QAKT"><thead><tr></tr></thead><tbody><tr><td colspan="5" style="text-align:center;padding:20px">Loading table...</td></tr></tbody></table></div></div>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="using-the-dbt-mcp-server-for-querying-data-via-the-dbt-semantic-layer"><strong>Using the dbt MCP server for querying data via the dbt Semantic Layer</strong><a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/introducing-dbt-mcp-server#using-the-dbt-mcp-server-for-querying-data-via-the-dbt-semantic-layer" class="hash-link" aria-label="Direct link to using-the-dbt-mcp-server-for-querying-data-via-the-dbt-semantic-layer" title="Direct link to using-the-dbt-mcp-server-for-querying-data-via-the-dbt-semantic-layer">​</a></h2>
<p>The <a href="https://www.getdbt.com/product/semantic-layer" target="_blank" rel="noopener noreferrer">dbt Semantic Layer</a> defines your organization's metrics and dimensions in a consistent, governed way. With the dbt MCP server, LLMs can understand and query these metrics directly, ensuring that AI-generated analyses are consistent with your organization's definitions.</p>
<ul>
<li><strong>For human stakeholders</strong>: Request metrics using natural language. Users can ask for "monthly revenue by region" and get accurate results that match your organization's standard metric definitions, with a <a href="https://roundup.getdbt.com/p/semantic-layer-as-the-data-interface" target="_blank" rel="noopener noreferrer">higher baseline of accuracy than LLM generated SQL queries</a>.</li>
<li><strong>For AI agent workflows</strong>: As agentic systems take action in the real world over a longer time horizon, they will need ways to understand the underlying reality of your business. From feeding into deep research style reports to feeding operational agents, the dbt Semantic Layer can provide a trusted underlying interface for LLM systems.</li>
</ul>
<p>By leveraging the dbt Semantic Layer through the MCP server, you ensure that LLM-generated analyses are based on rigorous definitions instantiated as code, flexibly available in any MCP-supported client.</p>
<h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="semantic-layer-tools">Semantic Layer Tools:<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/introducing-dbt-mcp-server#semantic-layer-tools" class="hash-link" aria-label="Direct link to Semantic Layer Tools:" title="Direct link to Semantic Layer Tools:">​</a></h3>
<div class="filterableTableContainer_mhtg"><table style="display:none"><thead><tr><th>Tool Name</th><th>Purpose</th><th>Output</th></tr></thead><tbody><tr><td><code>list_metrics</code></td><td>Provides an inventory of all available metrics in the dbt Semantic Layer</td><td>Complete list of metric names, types, labels, and descriptions</td></tr><tr><td><code>get_dimensions</code></td><td>Identifies available dimensions for specified metrics</td><td>List of dimensions that can be used to group/filter the specified metrics</td></tr><tr><td><code>query_metrics</code></td><td>Executes queries against metrics in the dbt Semantic Layer</td><td>Query results based on specified metrics, dimensions, and filters</td></tr></tbody></table><div class="tableWrapper_oiMt"><div class="searchBar_xnmH"><div class="searchContainer_fLyJ"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M416 208c0 45.9-14.9 88.3-40 122.7L502.6 457.4c12.5 12.5 12.5 32.8 0 45.3s-32.8 12.5-45.3 0L330.7 376c-34.4 25.2-76.8 40-122.7 40C93.1 416 0 322.9 0 208S93.1 0 208 0S416 93.1 416 208zM208 352a144 144 0 1 0 0-288 144 144 0 1 0 0 288z"></path></svg><input type="text" placeholder="Search table..." class="searchInput_xT8h" aria-label="Search table" value=""></div></div><table class="filterableTable_QAKT"><thead><tr></tr></thead><tbody><tr><td colspan="5" style="text-align:center;padding:20px">Loading table...</td></tr></tbody></table></div></div>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="using-the-dbt-mcp-server-for-sql-execution-to-power-text-to-sql"><strong>Using the dbt MCP server for SQL execution to power text to sql</strong><a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/introducing-dbt-mcp-server#using-the-dbt-mcp-server-for-sql-execution-to-power-text-to-sql" class="hash-link" aria-label="Direct link to using-the-dbt-mcp-server-for-sql-execution-to-power-text-to-sql" title="Direct link to using-the-dbt-mcp-server-for-sql-execution-to-power-text-to-sql">​</a></h2>
<p>While the dbt Semantic Layer provides a governed, metrics-based approach to data querying, there are many analytical needs that require more flexible, exploratory SQL queries. The dbt MCP server will soon include SQL validation and querying capabilities with rich context awareness.</p>
<ul>
<li><strong>For human stakeholders</strong>: Ask complex analytical questions that go beyond predefined metrics. Users can explore data freely while still benefiting from the LLM's understanding of their specific data models, ensuring that generated SQL is correct and optimized for your environment.</li>
<li><strong>For AI agent workflows</strong>: Generate and validate SQL against your data models automatically. Agents can create and execute complex queries that adapt to schema changes, optimize for performance, and follow your organization's SQL patterns and conventions.</li>
</ul>
<p>Unlike traditional SQL generation, queries created through the dbt MCP server will be aware of your specific data models, making them more accurate and useful for your particular environment. This capability is particularly valuable for data exploration, one-off analyses, and prototype development that might later be incorporated into your dbt project.</p>
<p>Currently SQL execution is managed through the dbt Show tool, over the near term we expect to release tooling that is more performant and fit to this precise use case.</p>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="using-the-dbt-mcp-server-for-project-execution"><strong>Using the dbt MCP server for project execution</strong><a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/introducing-dbt-mcp-server#using-the-dbt-mcp-server-for-project-execution" class="hash-link" aria-label="Direct link to using-the-dbt-mcp-server-for-project-execution" title="Direct link to using-the-dbt-mcp-server-for-project-execution">​</a></h2>
<p>The dbt MCP server doesn't just provide access to data—it also allows LLMs and AI agents to interact directly with dbt, executing commands and managing your project.</p>
<ul>
<li><strong>For human stakeholders</strong>: Trigger dbt commands through conversational interfaces without CLI knowledge. Users can ask to "run the daily models" or "test the customer models" and get clear explanations of the results, including suggestions for fixing any issues that arise.</li>
<li><strong>For AI agent workflows</strong>: Autonomously run dbt processes in response to events. Agents can manage project execution, automatically test and validate model changes, and even debug common issues without human intervention.</li>
</ul>
<p>While the discovery and query tools operate on top of <em>environments</em> as the context source, these execution tools interact directly with the CLI, both dbt Core and the Cloud CLI.</p>
<h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="project-execution-tools">Project Execution Tools<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/introducing-dbt-mcp-server#project-execution-tools" class="hash-link" aria-label="Direct link to Project Execution Tools" title="Direct link to Project Execution Tools">​</a></h3>
<div class="filterableTableContainer_mhtg"><table style="display:none"><thead><tr><th>Tool Name</th><th>Purpose</th><th>Output</th></tr></thead><tbody><tr><td><code>build</code></td><td>Executes the dbt build command to build the entire project</td><td>Results of the build process including success/failure status and logs</td></tr><tr><td><code>compile</code></td><td>Executes the dbt compile command to compile the project's SQL</td><td>Results of the compilation process including success/failure status and logs</td></tr><tr><td><code>list</code></td><td>Lists all resources in the dbt project</td><td>Structured list of resources within the project</td></tr><tr><td><code>parse</code></td><td>Parses the dbt project files</td><td>Results of the parsing process including success/failure status and logs</td></tr><tr><td><code>run</code></td><td>Executes the dbt run command to run models in the project</td><td>Results of the run process including success/failure status and logs</td></tr><tr><td><code>test</code></td><td>Executes tests defined in the dbt project</td><td>Results of test execution including success/failure status and logs</td></tr></tbody></table><div class="tableWrapper_oiMt"><div class="searchBar_xnmH"><div class="searchContainer_fLyJ"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M416 208c0 45.9-14.9 88.3-40 122.7L502.6 457.4c12.5 12.5 12.5 32.8 0 45.3s-32.8 12.5-45.3 0L330.7 376c-34.4 25.2-76.8 40-122.7 40C93.1 416 0 322.9 0 208S93.1 0 208 0S416 93.1 416 208zM208 352a144 144 0 1 0 0-288 144 144 0 1 0 0 288z"></path></svg><input type="text" placeholder="Search table..." class="searchInput_xT8h" aria-label="Search table" value=""></div></div><table class="filterableTable_QAKT"><thead><tr></tr></thead><tbody><tr><td colspan="5" style="text-align:center;padding:20px">Loading table...</td></tr></tbody></table></div></div>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="getting-started">Getting Started<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/introducing-dbt-mcp-server#getting-started" class="hash-link" aria-label="Direct link to Getting Started" title="Direct link to Getting Started">​</a></h2>
<p>The dbt MCP server is now available as an experimental release. To get started:</p>
<ol>
<li>Clone the repository from GitHub: <a href="https://github.com/dbt-labs/dbt-mcp" target="_blank" rel="noopener noreferrer">dbt-labs/dbt-mcp</a></li>
<li>Follow the installation instructions in the README</li>
<li>Connect your dbt project and start exploring the capabilities</li>
</ol>
<p>We're excited to see how the community builds with and extends the dbt MCP server. Whether you're building an AI-powered BI tool, an autonomous data agent, or just exploring the possibilities of LLMs in your data workflows, the dbt MCP server provides a solid foundation for bringing your dbt context to AI applications.</p>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="what-is-the-best-workflow-for-the-current-iteration-of-the-mcp-server">What is the best workflow for the current iteration of the MCP server?<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/introducing-dbt-mcp-server#what-is-the-best-workflow-for-the-current-iteration-of-the-mcp-server" class="hash-link" aria-label="Direct link to What is the best workflow for the current iteration of the MCP server?" title="Direct link to What is the best workflow for the current iteration of the MCP server?">​</a></h2>
<p>This early release is primarily meant to be used <em>on top of an existing dbt project to answer questions about your data and metadata -</em> roughly tracking towards the set of use cases described in this <a href="https://roundup.getdbt.com/p/how-ai-will-disrupt-bi-as-we-know" target="_blank" rel="noopener noreferrer">post</a> on the future of BI and data consumption.</p>
<p><em>Chat use case:</em></p>
<p>We suggest using Claude Desktop for this and creating a custom <a href="https://www.anthropic.com/news/projects" target="_blank" rel="noopener noreferrer">project</a> that includes a prompt explaining the use cases you are looking to cover.</p>
<p>To get this working:</p>
<ul>
<li>Follow the instructions in the Readme to install the MCP server</li>
<li>Validate that you have added the MCP config to your Claude desktop config. You should see ‘dbt’ when you go to Claude→Settings→Developer</li>
</ul>
<link href="/css/featherlight-styles.css" type="text/css" rel="stylesheet"><div class="
          docImage_EYbW
          
          
          
          
        " style="max-width:100%"><span><a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/introducing-dbt-mcp-server#" data-featherlight="/img/blog/2025-04-18-dbt-mcp-server/claudedesktop_settings_dbt_mcp.png"><img data-toggle="lightbox" alt="Claude Desktop – MCP server running in Developer settings" title="Claude Desktop – MCP server running in Developer settings" src="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/img/blog/2025-04-18-dbt-mcp-server/claudedesktop_settings_dbt_mcp.png?v=2"></a></span><span class="title_aGrV">Claude Desktop – MCP server running in Developer settings</span></div>
<ul>
<li>Create a new project called “analytics”. Give it a description of how an end user might interact with it.</li>
</ul>
<link href="/css/featherlight-styles.css" type="text/css" rel="stylesheet"><div class="
          docImage_EYbW
          
          
          
          
        " style="max-width:100%"><span><a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/introducing-dbt-mcp-server#" data-featherlight="/img/blog/2025-04-18-dbt-mcp-server/claudedesktop_project_card.png"><img data-toggle="lightbox" alt="Example Claude Desktop project connected to the dbt MCP server" title="Example Claude Desktop project connected to the dbt MCP server" src="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/img/blog/2025-04-18-dbt-mcp-server/claudedesktop_project_card.png?v=2"></a></span><span class="title_aGrV">Example Claude Desktop project connected to the dbt MCP server</span></div>
<ul>
<li><strong>Add a custom prompt explaining that questions in this project will likely be routed through the dbt MCP server.</strong> You’ll likely want to customize this to your particular organizational context.<!-- -->
<ul>
<li>For example: This conversation is connected to and knows about the information in your dbt Project via the dbt MCP server. When you receive a question that plausibly needs data from an external data source, you will likely want to use the tools available via the dbt MCP server to provide it.</li>
</ul>
</li>
</ul>
<p><em>Deployment considerations:</em></p>
<ul>
<li>This is an <em>experimental release</em>. We recommend that initial use should be focused on prototyping and proving value before rolling out widely across your organization.</li>
<li>Be particularly mindful with the project execution tools - remember that LLMs make mistakes and begin with permissions scoped so that you can experiment but not disrupt your data operations.</li>
<li>Start with the smallest possible use case that provides tangible value. Instead of giving this access to your entire production dbt Project, consider creating an upstream project that inherits a smaller subset of models and metrics that will power the workflow.</li>
<li>As of right now we don’t have perfect adherence for tool selection. In our testing, the model will sometimes cycle through several unnecessary tool calls or call them in the wrong order. While this can usually be fixed by more specific prompting by the end user, that goes against the spirit of allowing the model to dynamically select the right tool for the job. We expect this to be addressed over time via improvements in the dbt MCP Server, as well as client interfaces and the protocol itself.</li>
<li>Think carefully about the use cases for Semantic Layer tool vs. using the SQL execution tool. SQL execution is powerful but less controllable. We’re looking to do a lot of hands on testing to begin to develop heuristics about when SQL execution is the best option, when to bake logic into the Semantic Layer and whether there are new abstractions that might be needed for AI workflows.</li>
<li>Tool use is powerful because it can link multiple tools together. What tools complement the dbt MCP Server? How can we use this to tie our structured data into other workflows?</li>
</ul>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="the-future-of-the-dbt-mcp-and-the-correct-layers-of-abstraction-for-interfacing-with-your-data">The future of the dbt MCP and the correct layers of abstraction for interfacing with your data<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/introducing-dbt-mcp-server#the-future-of-the-dbt-mcp-and-the-correct-layers-of-abstraction-for-interfacing-with-your-data" class="hash-link" aria-label="Direct link to The future of the dbt MCP and the correct layers of abstraction for interfacing with your data" title="Direct link to The future of the dbt MCP and the correct layers of abstraction for interfacing with your data">​</a></h2>
<p>We are in the <em>very</em> early days of MCP as a protocol and determining how best to connect your structured data to LLM systems. This is an extremely exciting, dynamic time where we are working out, in real time, how to best serve this data and context.</p>
<p>We have high confidence that the approach of serving context to your AI systems via dbt will prove a durable piece of this stack. As we work with the Community on implementing this in real world use cases, it is quite likely that the details of the implementation and how you access it may change. Here are some of the areas we expect this to evolve.</p>
<p><strong>Determining the best source of context for the dbt MCP</strong>
You’ll notice that these tools have two broad information inputs - dbt Cloud APIs and the dbt CLI. We expect to continue to build on both of these, specifically with dbt Cloud APIs to serve the abstraction of choice when it is desirable to operate off of a specific <a href="https://docs.getdbt.com/docs/dbt-platform-environments" target="_blank" rel="noopener noreferrer">environment</a>.</p>
<p>There will be other use cases, specifically for dbt development, when you’ll want to operate based off of your current working context, we’ll be releasing tooling for that in the near future (and welcome Community submitted ideas and contributions). We’re looking forward to trying out alternative methods here and looking forward to hearing from the Community how you would like to have this context loaded in. Please feel free to experiment and share your findings with us.</p>
<p><strong>Determining the most useful tools for the dbt MCP</strong></p>
<p>What are the best and most useful set of tools to enable human in the loop and AI driven LLM access to structured data? The dbt MCP server presents our early explorations, but we anticipate that the Community will find many more.</p>
<p><strong>How to handle hosting, authentication, RBAC and more</strong></p>
<p>Currently the dbt MCP server is locally hosted, with access management via scoped service tokens from dbt Cloud or locally configured via your CLI. We expect there to be three levels via which we will continue to build out systems to make this not only safe and secure, but tailored to the needs of the specific user (human or agent) accessing the MCP.</p>
<ol>
<li>Hosting of the MCP: In the near future we will have a Cloud hosted version of the MCP alongside the current local MCP</li>
<li>Managing data access with the MCP: We are committed to offering safe and trustworthy data and data asset access (think OAuth support and more)</li>
<li>User and domain level context: Over the longer run we are looking into ways to provide user and domain specific knowledge about your data assets to the systems as they are querying it.</li>
</ol>
<p>Expect to hear more on this front on <a href="https://www.getdbt.com/resources/webinars/2025-dbt-cloud-launch-showcase" target="_blank" rel="noopener noreferrer">5/28</a>.</p>
<p>This is a new frontier for the whole Community. We need to be having open, honest discussions about how to integrate these systems into our existing workflows and open up new use cases.</p>
<p>To join the conversation, head over to #tools-dbt-mcp in the dbt Community Slack.</p>]]></content>
        <author>
            <name>Jason Ganz</name>
        </author>
        <category label="ai" term="ai"/>
        <category label="data ecosystem" term="data ecosystem"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Establishing dbt Cloud: Securing your account through SSO & RBAC]]></title>
        <id>https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-cloud-sso-rbac</id>
        <link href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-cloud-sso-rbac"/>
        <updated>2025-04-17T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[How to configure dbt Cloud with SSO & RBAC]]></summary>
        <content type="html"><![CDATA[<p>As a dbt Cloud admin, you’ve just upgraded to dbt Cloud on the <a href="https://www.getdbt.com/pricing" target="_blank" rel="noopener noreferrer">Enterprise plan</a> - <strong>congrats</strong>! dbt Cloud has a lot to offer such as <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/docs/deploy/about-ci">CI/CD</a>, <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/docs/deploy/deployments">Orchestration</a>, <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/docs/explore/explore-projects">dbt Explorer</a>, <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/docs/use-dbt-semantic-layer/dbt-sl">dbt Semantic Layer</a>, <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/best-practices/how-we-mesh/mesh-1-intro">dbt Mesh</a>, <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/docs/platform/canvas">Visual Editor</a>, <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/docs/platform/wizard-platform">dbt Copilot</a>, and so much more. <em><strong>But where should you begin?</strong></em></p>
<p>We strongly recommend as you start adopting dbt Cloud functionality to make it a priority to set up Single-Sign On (SSO) and Role-Based Access Control (RBAC). This foundational step enables your organization to keep your data pipelines secure, onboard users into dbt Cloud with ease, and optimize cost savings for the long term.</p>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="authentication-vs-authorization">Authentication vs. Authorization<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-cloud-sso-rbac#authentication-vs-authorization" class="hash-link" aria-label="Direct link to Authentication vs. Authorization" title="Direct link to Authentication vs. Authorization">​</a></h2>
<p>Before we dig into SSO, RBAC, and more — let’s go over how they map into two foundational security concepts.</p>
<ul>
<li><strong>Authentication:</strong> <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-cloud-sso-rbac#single-sign-on-sso">SSO</a> is configured to gate authentication - it verifies (via an IdP) that users are who they say they are and can log into the specified dbt Cloud account.</li>
<li><strong>Authorization:</strong> <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-cloud-sso-rbac#role-based-access-control-via-idp">RBAC</a> is an authorization model - it controls what users can see and do within dbt Cloud based on their assigned licenses, groups, and permission sets.</li>
</ul>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="single-sign-on-sso">Single-Sign On (SSO)<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-cloud-sso-rbac#single-sign-on-sso" class="hash-link" aria-label="Direct link to Single-Sign On (SSO)" title="Direct link to Single-Sign On (SSO)">​</a></h2>
<p>Your SSO configuration steps will depend on your IdP, so we encourage you to start at our <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/docs/platform/manage-access/sso-overview">SSO Overview</a> page and find the IdP-specific doc under that section that’s specific to your setup.</p>
<p>Regardless of what IdP you use, one of the first things you should do as a dbt Cloud admin is set the <strong>login slug</strong> value. This should be a <em>unique company identifier</em>.</p>
<p>Keep in mind that whatever you set, the slug will be appended to the end of the SSO login URL that your users will use to sign into dbt Cloud. For example:</p>
<ul>
<li>If I set my login slug to <code>mynewco</code></li>
<li>My SSO login URL will look something like <code>https://cloud.getdbt.com/enterprise-login/mynewco</code>.</li>
</ul>
<p>At first glance, this screen has a lot of info and fields — but with the <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/docs/platform/manage-access/sso-overview">SSO docs</a> in hand, dbt Cloud admins are ready to start setting up smooth, scalable workflows.</p>
<link href="/css/featherlight-styles.css" type="text/css" rel="stylesheet"><div class="
          docImage_EYbW
          
          
          
          
        " style="max-width:85%"><span><a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-cloud-sso-rbac#" data-featherlight="/img/blog/2025-04-10-sso-and-rbac/1_sso_config.png"><img data-toggle="lightbox" alt="dbt Cloud's SSO configuration page" title="dbt Cloud's SSO configuration page" src="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/img/blog/2025-04-10-sso-and-rbac/1_sso_config.png?v=2"></a></span><span class="title_aGrV">dbt Cloud's SSO configuration page</span></div>
<p>Let’s break this down at a high level to make it more digestible:</p>
<ol>
<li>After setting the desired login slug, a <em>dbt Cloud admin</em> will go to the dbt Cloud SSO configuration page and copy/paste everything under the <strong>Identity provider values</strong> section and will share the values with the <em>IdP admin</em>.</li>
<li>The <em>IdP admin</em> will create a <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/docs/platform/manage-access/set-up-sso-saml-2.0#creating-the-application">dbt Cloud app</a> and then provide the values under the <strong>dbt configuration</strong> section to the <em>dbt Cloud admin</em>.<!-- -->
<div class="theme-admonition theme-admonition-tip admonition_xJq3 alert alert--success"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>tip</div><div class="admonitionContent_BuS1"><p>Refer to the appropriate setup docs for <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/docs/platform/manage-access/set-up-sso-google-workspace">Google Workspace</a>, <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/docs/platform/manage-access/set-up-sso-okta">Okta</a>, <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/docs/platform/manage-access/set-up-sso-microsoft-entra-id">Microsoft Entra ID</a>, or <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/docs/platform/manage-access/set-up-sso-saml-2.0">SAML 2.0</a>.</p></div></div>
</li>
<li>The <em>dbt Cloud admin</em> will fill in those values into the SSO configuration page under the <strong>dbt configuration</strong> section and click <strong>Save</strong> to complete the process.</li>
</ol>
<p>After completing this process:</p>
<ul>
<li>We <em>strongly</em> advise you validate the SSO flow is working by pasting the SSO login URL (it should look like <code>https://cloud.getdbt.com/enterprise-login/dbtlabs</code>) into your web browser’s private window</li>
<li>And try to log into your account via the IdP.</li>
<li>If the SSO flow isn’t working as expected, an account admin will still be able to log in with a password to correct the configuration.</li>
</ul>
<div class="theme-admonition theme-admonition-tip admonition_xJq3 alert alert--success"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>tip</div><div class="admonitionContent_BuS1"><p>Be aware of our <a href="https://docs.getdbt.com/docs/platform/manage-access/sso-overview#sso-enforcement" target="_blank" rel="noopener noreferrer">SSO enforcement policy</a> — once SSO is configured, all non-admin users will have to log in via SSO as a security best practice, while account admins, by default, can still authenticate with a password in lieu of <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/docs/platform/manage-access/mfa">multi-factor authentication (MFA)</a>.</p></div></div>
<p>Once you've set up SSO successfully, you have additional ways to onboard your users into dbt Cloud on top of sending out an email invite:</p>
<ul>
<li>Provide users the SSO login URL to access dbt Cloud. This is also known as the <em>SP-initiated flow</em> (SP stands for Service Provider; in this case, it would be dbt Cloud).</li>
<li>Provision the dbt Cloud for users to access on their IdP’s dashboard. This is also known as the <em>IdP-initiated flow</em>.</li>
</ul>
<link href="/css/featherlight-styles.css" type="text/css" rel="stylesheet"><div class="
          docImage_EYbW
          
          
          
          
        " style="max-width:85%"><span><a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-cloud-sso-rbac#" data-featherlight="/img/blog/2025-04-10-sso-and-rbac/2_sso_flows.png"><img data-toggle="lightbox" alt="SSO flows into dbt Cloud" title="SSO flows into dbt Cloud" src="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/img/blog/2025-04-10-sso-and-rbac/2_sso_flows.png?v=2"></a></span><span class="title_aGrV">SSO flows into dbt Cloud</span></div>
<p>Get stuck setting up SSO? <a href="mailto:support@getdbt.com" target="_blank" rel="noopener noreferrer">Open a support ticket</a>, and one of our Customer Solutions Engineers will be happy to help you!</p>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="licenses-and-groups">Licenses and Groups<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-cloud-sso-rbac#licenses-and-groups" class="hash-link" aria-label="Direct link to Licenses and Groups" title="Direct link to Licenses and Groups">​</a></h2>
<p>In dbt Cloud, there are two main levers to control user access:</p>
<ul>
<li><a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-cloud-sso-rbac#licenses">Licenses</a></li>
<li><a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-cloud-sso-rbac#groups">Groups</a></li>
</ul>
<p>As a prerequisite, these all should be set <em>before</em> configuring RBAC. Let’s get into these!</p>
<h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="licenses">Licenses<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-cloud-sso-rbac#licenses" class="hash-link" aria-label="Direct link to Licenses" title="Direct link to Licenses">​</a></h3>
<p>There are three <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/docs/platform/manage-access/seats-and-users">license types</a> in dbt Cloud:</p>
<ul>
<li><strong>Developer:</strong> User can be granted&nbsp;<em>any</em>&nbsp;permissions.</li>
<li><strong>Read-Only:</strong> User has read-only permissions applied to all dbt Cloud resources regardless of the role-based permissions that the user is assigned.</li>
<li><strong>IT:</strong> User has Security Admin and Billing Admin&nbsp;permissions&nbsp;applied, regardless of the group permissions assigned.</li>
</ul>
<p>Odds are that the majority of your users will be developers or analysts who’ll need Developer licenses. You can assign default licenses to users based on the groups that they’re in on the IdP side under <strong>Account Settings</strong> --&gt; <strong>Groups &amp; Licenses</strong> --&gt; <strong>License mappings</strong>.</p>
<link href="/css/featherlight-styles.css" type="text/css" rel="stylesheet"><div class="
          docImage_EYbW
          
          
          
          
        " style="max-width:85%"><span><a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-cloud-sso-rbac#" data-featherlight="/img/blog/2025-04-10-sso-and-rbac/3_license_mapping_example.png"><img data-toggle="lightbox" alt="An example license mapping" title="An example license mapping" src="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/img/blog/2025-04-10-sso-and-rbac/3_license_mapping_example.png?v=2"></a></span><span class="title_aGrV">An example license mapping</span></div>
<p>If a user is in multiple groups with different license types assigned, they will be granted the highest license type — Developer.</p>
<h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="groups">Groups<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-cloud-sso-rbac#groups" class="hash-link" aria-label="Direct link to Groups" title="Direct link to Groups">​</a></h3>
<p>Groups are used to manage permissions. They define what a user can see and do across projects and environments. We recommend reviewing our <a href="https://docs.getdbt.com/docs/platform/manage-access/enterprise-permissions" target="_blank" rel="noopener noreferrer">available permissions sets</a> and determining which are applicable to your dbt Cloud user base.</p>
<p>Keep in mind group permissions are additive in nature for users that belong to more than one group — meaning if a user belongs to multiple groups, they'll inherit all assigned permissions.</p>
<p>Navigating to Groups &amp; Licenses page in dbt Cloud, you’ll see three default groups — Everyone, Member, and Owner. There’s also an option to create your own groups on the top right.</p>
<link href="/css/featherlight-styles.css" type="text/css" rel="stylesheet"><div class="
          docImage_EYbW
          
          
          
          
        " style="max-width:85%"><span><a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-cloud-sso-rbac#" data-featherlight="/img/blog/2025-04-10-sso-and-rbac/4_default_dbt_cloud_groups.png"><img data-toggle="lightbox" alt="The out-of-the-box dbt Cloud groups you may use" title="The out-of-the-box dbt Cloud groups you may use" src="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/img/blog/2025-04-10-sso-and-rbac/4_default_dbt_cloud_groups.png?v=2"></a></span><span class="title_aGrV">The out-of-the-box dbt Cloud groups you may use</span></div>
<p>Here’s a brief primer on the default groups:</p>
<ul>
<li><strong>Owner:</strong> This group is for individuals responsible for the entire account and will give them elevated account admin privileges. You cannot change the permissions.</li>
<li><strong>Member:</strong> This group is for the general members of your organization, who will also have full developer access to the account. You cannot change the permissions. By default, dbt Cloud adds new users to this group.</li>
<li><strong>Everyone:</strong> A general group for all members of your organization. Customize the permissions to fit your organizational needs. By default, dbt Cloud adds new users to this group and only grants user access to their personal profile.</li>
</ul>
<p>While we recommend creating your own groups and deleting the defaults to better tailor it to your business’ needs, you should only delete the defaults <em>after</em> your own groups have been created and permission sets have been associated with them. These default groups are available to you as a means of getting users started in dbt Cloud. To sum up what they do, the Owner group will give users full account admin access while Everyone and Member groups will give users full developer access.</p>
<p>To help get you started, these are the main permission sets that should be assigned to most users:</p>
<div class="filterableTableContainer_mhtg"><table style="display:none"><thead><tr><th><strong>User persona</strong></th><th><strong>Permission set</strong></th></tr></thead><tbody><tr><td>dbt Cloud Admin</td><td>Account Admin</td></tr><tr><td>dbt Developer</td><td>Developer</td></tr><tr><td>dbt Analyst</td><td>Analyst</td></tr></tbody></table><div class="tableWrapper_oiMt"><div class="searchBar_xnmH"><div class="searchContainer_fLyJ"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M416 208c0 45.9-14.9 88.3-40 122.7L502.6 457.4c12.5 12.5 12.5 32.8 0 45.3s-32.8 12.5-45.3 0L330.7 376c-34.4 25.2-76.8 40-122.7 40C93.1 416 0 322.9 0 208S93.1 0 208 0S416 93.1 416 208zM208 352a144 144 0 1 0 0-288 144 144 0 1 0 0 288z"></path></svg><input type="text" placeholder="Search table..." class="searchInput_xT8h" aria-label="Search table" value=""></div></div><table class="filterableTable_QAKT"><thead><tr></tr></thead><tbody><tr><td colspan="5" style="text-align:center;padding:20px">Loading table...</td></tr></tbody></table></div></div>
<p>You can also use groups to control which projects and environments users can access.</p>
<link href="/css/featherlight-styles.css" type="text/css" rel="stylesheet"><div class="
          docImage_EYbW
          
          
          
          
        " style="max-width:85%"><span><a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-cloud-sso-rbac#" data-featherlight="/img/blog/2025-04-10-sso-and-rbac/5_new_dbt_cloud_group.png"><img data-toggle="lightbox" alt="Creating a new dbt Cloud group" title="Creating a new dbt Cloud group" src="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/img/blog/2025-04-10-sso-and-rbac/5_new_dbt_cloud_group.png?v=2"></a></span><span class="title_aGrV">Creating a new dbt Cloud group</span></div>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="role-based-access-control-via-idp">Role-Based Access Control via IdP<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-cloud-sso-rbac#role-based-access-control-via-idp" class="hash-link" aria-label="Direct link to Role-Based Access Control via IdP" title="Direct link to Role-Based Access Control via IdP">​</a></h2>
<p>If you made it this far, thanks for staying with me here! We’re now ready to configure RBAC, which assign users to the right groups and effectively the right permission sets after they authenticate into dbt Cloud. This hinges on the <em>SSO group mapping(s)</em> you’ll find within a group.</p>
<p>As an example, let’s say that I want specific users in this group where the SSO group mapping is <code>dbt-developer</code>. Note that you can also specify more than one.</p>
<link href="/css/featherlight-styles.css" type="text/css" rel="stylesheet"><div class="
          docImage_EYbW
          
          
          
          
        " style="max-width:85%"><span><a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-cloud-sso-rbac#" data-featherlight="/img/blog/2025-04-10-sso-and-rbac/6_sso_group_mapping.png"><img data-toggle="lightbox" alt="Configuring a SSO group mapping within a group" title="Configuring a SSO group mapping within a group" src="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/img/blog/2025-04-10-sso-and-rbac/6_sso_group_mapping.png?v=2"></a></span><span class="title_aGrV">Configuring a SSO group mapping within a group</span></div>
<p>Here’s what we do to make it happen:</p>
<ol>
<li>Have your IdP admin create a <code>dbt-developer</code> group in the IdP.</li>
<li>Assign users who should be in the dbt Cloud group to that IdP group.</li>
<li>Have users sign into dbt Cloud to confirm they get assigned to that group.</li>
</ol>
<p>Easy enough, right? Just make sure these two conditions are checked for RBAC to work properly between your IdP and dbt Cloud:</p>
<ul>
<li>Group names must be an exact match</li>
<li>Group names have the same casing</li>
</ul>
<link href="/css/featherlight-styles.css" type="text/css" rel="stylesheet"><div class="
          docImage_EYbW
          
          
          
          
        " style="max-width:85%"><span><a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-cloud-sso-rbac#" data-featherlight="/img/blog/2025-04-10-sso-and-rbac/7_okta_sso_group_mapping_example.png"><img data-toggle="lightbox" alt="Making a SSO group mapping work with your idenity provider" title="Making a SSO group mapping work with your idenity provider" src="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/img/blog/2025-04-10-sso-and-rbac/7_okta_sso_group_mapping_example.png?v=2"></a></span><span class="title_aGrV">Making a SSO group mapping work with your idenity provider</span></div>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="automate-sso--rbac-introducing-scim">Automate SSO &amp; RBAC: Introducing SCIM<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-cloud-sso-rbac#automate-sso--rbac-introducing-scim" class="hash-link" aria-label="Direct link to Automate SSO &amp; RBAC: Introducing SCIM" title="Direct link to Automate SSO &amp; RBAC: Introducing SCIM">​</a></h2>
<p>We have exciting news — <a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/docs/platform/manage-access/scim">System for Cross-Domain Identity Management) (SCIM)</a> support will be generally available in May 2025 (for SCIM-compliant IdPs &amp; Okta)! If you’re unfamiliar with SCIM, you can think of it as automated user provisioning in dbt Cloud. It makes user data more secure and simplifies the admin and user experience by automating the user identity and group lifecycle.</p>
<p>Here’s why you should care about SCIM as a dbt Cloud admin:</p>
<ol>
<li><strong>Improved Admin and end user experience</strong> — Through automating user onboarding and offboarding, SCIM saves time for dbt Cloud admins that are managing multiple users on a weekly basis. If a user is added or removed in the IdP, their license and user account is automatically added/removed from dbt Cloud.</li>
<li><strong>Simplified RBAC with group management</strong> — Admins can simplify access control management by using SCIM to update group membership. Currently, SSO group mapping enables admins to add new users to groups when they are JIT provisioned. SCIM would build on that functionality to allow group management not only for new users but also for existing users.</li>
</ol>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="closing-thoughts">Closing thoughts<a href="https://docs-getdbt-com-git-mirnawong1-patch-27-dbt-labs.vercel.app/blog/dbt-cloud-sso-rbac#closing-thoughts" class="hash-link" aria-label="Direct link to Closing thoughts" title="Direct link to Closing thoughts">​</a></h2>
<p>Securing your account through SSO and RBAC should be one of your first priorities after getting on the Enterprise plan.</p>
<p>Not only does it keep your data safe, it allows you to onboard users into your account at scale. While it may be just the beginning of your dbt Cloud journey, putting in the work to check off this crucial step will establish that users are leveraging dbt responsibly at an enterprise grade level!</p>]]></content>
        <author>
            <name>Brian Jan</name>
        </author>
        <category label="dbt tutorials" term="dbt tutorials"/>
    </entry>
</feed>