SQL, Typescript, and Agents
How SQL’s Typescript moment will help agents just as much as it’ll help humans.
Sorry for the radio silence here. It’s been a good little while since I wrote. The fact that there may have been a few things going on notwithstanding, I did miss the regular routine and discipline. Excited to be back, and I’m going to try to keep a more consistent pace moving forwards. There is so much going on, so much to say.
Onwards.
- Tristan
===
I’ll be honest…a few weeks ago I didn’t know that much about TypeScript. I’m not a big front end guy, and now with vibe coding I don’t imagine I’ll ever learn to write JavaScript. But someone on our team made a comment to me recently—essentially, “dbt’s Fusion engine is doing for SQL what TypeScript did for JavaScript,” which wormed its way into my brain.
It turns out…it’s a really good comparison. And today I wanted to spend some time exploring this thought. Because I think it matters a lot to both the dbt developer ecosystem for humans but even more so for agents.
The TypeScript Story
In October 2012, Microsoft released TypeScript 0.8 after two years of internal development. Anders Hejlsberg, the architect, was modest about what success would look like. His stated goal: “Maybe we’ll get 25% of the JavaScript community to take an interest — that would be success.”
The JavaScript community’s reaction was, roughly: “Why would I want this? JS works fine. I don’t need types. Types are what you use in Java, and nobody is having fun in Java.”
They weren’t wrong. JavaScript is flexible, fast, forgiving; you prototype quickly, throw things together, ship. That dynamic nature isn’t a flaw to be corrected. Hejlsberg’s team knew this, which is why TypeScript was a superset: you could opt in gradually, one file at a time, without torching the ecosystem you’d built.
Why types matter (even if you’ve never declared one)
If you’ve written mostly SQL and Jinja, you may have never declared a type. SQL doesn’t ask you to (except, of course, when you create columns!). You write select revenue from orders and the database figures out the rest at runtime. This feels like a feature (and it is!). But it also means no tool can look at your code before execution and know much about it.
That’s what types buy you: pre-runtime knowledge. When a language knows that orders.revenue is a decimal and orders.customer_id is an integer, tools can tell you at write time whether you’re doing something nonsensical: averaging a customer ID, joining on a column that doesn’t exist in the downstream model, passing the wrong type to a function. More importantly, it means IDEs can offer autocomplete that actually understands your schema, catch errors the moment you type them, and perform refactoring without guessing at what each reference means.
Coming back to Javascript: developers have adopted types, and TypeScript, not because of some I-should-have-included-types-from-the-beginning mea culpa from Brendan Eich. Rather, the TypeScript tooling ecosystem just outstripped that of Javascript and developers migrated as a result. Types made large codebases refactorable without fear, developers moved faster, stayed in flow state, and spent less time on stupid crap. The magic, as Hejlsberg put it, was making TypeScript “feel like JavaScript, but with superpowers.”
So: the types weren’t the point, they were just what made the tooling possible. Today TypeScript is the most-used language on GitHub, with adoption that went from 12% of developers in 2017 to 37% in 2024.
SQL Is Living the Same Story
SQL has been around since the 1970s. It’s the most widely-used language in data by a significant margin. And like JavaScript before TypeScript, it has thrived on flexibility: you write queries without defining schemas upfront, without a local compiler. Just write the SQL, hit run, see what comes back.
That super-simple DX is a big reason SQL is everywhere.
It’s also exactly why SQL tooling has historically stayed thin. Decades in, most SQL editors still offer little more than syntax highlighting and basic autocomplete, while JavaScript developers got full Intellisense. Without type information, tools can’t know what a column reference means, whether a join is valid, or whether a function exists in the target dialect. This is why AI agents working with SQL today hit the same ceiling JavaScript developers hit as their codebases scaled: at a certain level of complexity, you need language features that make your development loop both safer and, as a result, faster.
SQL has historically had none of this. Write a transformation, run it against the warehouse, get rows back or an error. The loop is slow, expensive, and blind to structural problems before runtime. An agent generating SQL has no way to know if what it wrote is correct until it hits production data.
Fusion: Mature Language Features for SQL & dbt
dbt’s Fusion engine is, at its core, the TypeScript transition applied to SQL. A real SQL compiler that parses, understands, and type-checks SQL across multiple warehouse dialects before anything runs. It uses the Arrow type system from drivers through adapters into the compiler and runtime, producing a logical plan via static analysis for every rendered query in a project.
(Just the idea of layering a single type system across all existing data platforms is a fascinating problem that I have every confidence we don’t yet fully understand the significance of! But I digress…)
And Fusion ships with a language server. Real-time error detection. Autocomplete that understands your models and columns. Hover insights. Inline lineage. Refactoring that propagates changes to downstream automatically. Everything that made TypeScript-in-VS-Code feel categorically different from JavaScript-in-a-text-editor.
Author’s note! Fusion is officially going GA in the next ~2 months. Public Preview has been highly productive and we’re now in the final process of pre-GA refinement. It’s ready for production deployments today (over 3k projects running it in prod today) but if you’re waiting for GA that’ll come soon.
The Agentic Development Loop
Ok, cool. That is great. But I don’t actually write my own code anymore since Opus 4.6. So: do I actually care about language DX?
I do. And you should too.
AI coding agents work in loops. Write something, check whether it’s right, fix it, check again. The quality of those loops is what determines whether agents produce reliable output or garbage.
Spotify’s engineering team documented this directly: without feedback mechanisms, “the agents often produce code that simply doesn’t work.” What makes their agents reliable is a verification loop — compilers, formatters, tests — running after every change. Agents can confirm they’re on the right track before committing.
Anthropic agrees: in December 2025, Claude Code shipped native LSP support. When Claude Code modifies a file, it can query the language server for diagnostics from a language server in milliseconds, with type errors, undefined references, and structural problems flagged before anything runs. The tight feedback loop allows agents to move faster, with higher trust, and use fewer tokens. Same model, better infra >> better performance.
A language server and type system give SQL agents the first part of that loop: fast, structural feedback on whether what they wrote is valid. Meaningful improvement over the current state. But structural soundness is necessary, not sufficient. Correctness requires not only structural correctness, but also semantic correctness.
Agents Need Tests!
dbt tests come in two types: data tests (designed to test underlying data) and unit tests (designed to test code). And they can be written with two specific intents:
structural tests: designed to test that data adheres to technical specifications, like uniqueness and referential integrity
semantic tests: designed to test business logic, like making sure debits equal credits
Most dbt projects focus heavily on structural data tests. We analytics engineers love testing to make sure that our models generate data that follows obvious structural rules. And this is good insofar as it goes. But it’s not enough for agents. Wes McKinney talked about this in his recent Python is Dead. Long Live Python! podcast: without semantic tests, agents have no signal for whether what the agent wrote is actually correct. You get structurally valid code that is logically wrong.
Unfortunately, most dbt projects have very few unit tests defined. This is not shocking; unit tests (pre-agent) took a long time to build, and they weren’t something that analytics engineers were in the habit of doing (first introduced in 1.8, in May of 2024). But this is, IMO, one of the biggest friction points to getting agents that can safely operate inside of large, complex data repos. Tests asserting semantic correctness would make long-running data coding agents exciting rather than stressful.
Of course, for a great agentic development loop the tests also have to run really damn fast. And we’ll have a lot more to say on that soon! 🧪🧪
For now, we believe that Fusion’s compiler and LSP unlock an absolutely next-level set of capabilities for both humans and agents. And we’re pushing hard to improve the entire development loop with tests that are easier to author and run fast.
This is the most fun I’ve had writing dbt code for … I don’t know. A long time. I hope you’re having as much fun as I am.
- Tristan
