Jamie Turner's avatar
Jamie Turner
4 months ago

3 Reasons Why AI Agents Love Convex

"Convex is agent-friendly." "It let me write code instead of worrying about SQL." "Agents are really good at writing Convex apps." That kind of comment keeps showing up, and it raises an obvious question: aren't agents supposed to be good at everything? If an LLM is meant to be an all-powerful developer, it shouldn't need a particular backend to write decent software. But LLMs aren't good at everything. Three specific things about Convex's design make agents succeed anyway, and they go a long way toward explaining why Convex agents work as well as they do. I'm Jamie Turner, Convex's CEO, and I'll walk through what those three are.

What LLMs are good at, and where they fall down

Start with what LLMs are actually good at. They're incredibly broad, far broader than any individual person could be. An LLM probably knows Vue better than I do, and it knows more about chemistry than most chemists know about web development. That breadth is real. Most of us just don't get much use out of it day to day, because most days we're working in one narrow domain. The fact that a model can also write competent Shakespearean poetry doesn't help me much when I'm building a web app.

Depth is a different story. Within a specific domain, picking the right best practice for the right problem, LLMs are weaker than true experts. That's part of why new engineers tend to overrate them and experienced engineers tend to underrate them. New engineers haven't yet built the pattern-matching that spots where a model's suggestion is subtly wrong. People outside a domain are more impressed by an LLM's competence in it than people inside it are, because outsiders can't see where it's cutting corners.

Speed is the real superpower, especially speed relative to cost. LLMs produce code far faster than a person can. That speed is useful even when breadth and depth aren't the deciding factor.

Then there's context, the biggest practical limitation of the bunch. If something is well-represented in the training data, LLMs are excellent at it. Once you get project-specific, meaning last-mile reasoning about a particular codebase, models are still much worse than strong engineers.

A good engineer carries a compressed mental model of a large codebase: which parts do which job, where to look when something needs to change, how a change in one place ripples through the rest. LLMs are much worse at building and using that kind of compressed artifact right now. That's a big part of why they're great at to-do apps and so much shakier on anything with real depth. A to-do app is a well-known pattern, it generates fast, and the context to build one is small enough that a model can hold all of it at once.

Why Convex, and not jQuery or classic backends

This context weakness explains an odd pattern. jQuery has been around far longer than Convex, with vastly more jQuery code in any model's training set. Even so, LLMs are worse at building working jQuery sites than at building Convex apps. The same holds for classic distributed backends: a constellation of application servers, caches, queues, and databases. Models can produce that kind of code, but it frequently doesn't work.

The comparison that actually explains this is React, not the raw amount of training data. React's central contribution to web development was composition. It's literally named after components, and that's the same problem Convex solves on the backend. Three specific parts of that design are what let Convex agents succeed where they struggle everywhere else.

Trick one: everything is code, so agents get real feedback

Agents are probabilistic. The gap between the best model and an average one is large, and even the best models get things wrong regularly. Types are one of the most effective feedback loops an agent has: change something, run it, read the type error, correct it, repeat.

In Convex, the schema, the HTTP routes, the background jobs, even agentic workflows installed as npm packages, are all defined in code. They live in the same codebase, sharing one type system all the way back to the database schema. When an agent generates something slightly wrong, it gets a type error telling it exactly what to fix. Once the compiler is satisfied, the project is usually close to correct.

Something like this, in a Convex app, is one continuous, typed path from database to function to client:

1// convex/schema.ts
2export default defineSchema({
3  tasks: defineTable({
4    title: v.string(),
5    status: v.union(v.literal("todo"), v.literal("in_progress"), v.literal("done")),
6  }),
7});
8
9// convex/tasks.ts
10export const setStatus = mutation({
11  args: { id: v.id("tasks"), status: v.union(v.literal("todo"), v.literal("in_progress"), v.literal("done")) },
12  handler: async (ctx, { id, status }) => {
13    await ctx.db.patch(id, { status });
14  },
15});
16
17// In the client
18const setStatus = useMutation(api.tasks.setStatus);
19// TypeScript rejects a typo like status: "donee" before the agent ever runs the code
20

Traditional backends don't offer that. A typical production setup scatters its configuration across surfaces that have nothing to do with each other:

What needs configuringWhere that config lives
HTTP trafficAn Nginx config file
InfrastructureTerraform
Container orchestrationKubernetes YAML
QueuesA web dashboard
Everything elseAn assortment of AWS services

Each one has its own language and its own dashboard, and an agent has no clean way to read or manipulate most of them. Worse, some of it only matters in production, so the feedback an agent gets in development doesn't necessarily hold once the app ships.

In Convex, dev and prod work the same way, in the same language, with the same types. There's no gap between what an agent learns while iterating and what's true once the app is live.

A typical full-stack app also runs a different type system at every layer: client-side state, HTTP parameters, a backend language, an ORM or something like tRPC bridging to SQL types. Convex collapses all of that into one thing. Change a database type and the UI code shows a type error right away, and an agent sees that error the same way you would. Propagating a state change from the schema all the way down to the client, in full, is unusually complete in Convex compared to most stacks.

Convex is also starting to extend this feedback loop into runtime information. In a typical distributed system, no one, sometimes not even the original developers, fully understands how the cache, the queue, the app server, and the database relate to each other under load. Convex ingests the entire typed data flow, front end and back end together, so it can tell an agent exactly what's slow and why. Its execution is also largely deterministic, so it can replay production traffic against a proposed change and confirm it got faster without changing behavior. That capability is early, but it points at the same idea. Give the agent a real signal, and it can act on it.

Trick two: the backend is reactive, so agents can reason locally

Local reasoning is what composition actually buys you, and it fixes the worst weakness LLMs have: limited context. When local reasoning holds, everything an agent needs to make a correct change sits inside the one function or component it's already looking at.

The simplest React component, the one every tutorial starts with, takes a value and renders it. It doesn't know or care how that value gets set. It could be rendering millions of instances. It only has to guarantee that whatever value it's given, it renders correctly, and React re-runs it when the value changes. The code that updates that value, somewhere else entirely, doesn't need to know how many components are reading it either.

Producers don't need to know about consumers, and consumers don't need to know about producers. That's what lets people make small, local changes to huge React codebases without holding the whole thing in their head. It's also exactly what an LLM needs, because a model does best when it can look at one function, generate a type-correct transformation, and be done.

Convex extends that same guarantee to the backend, because the database itself is reactive. You can write a Convex function without tracking every other mutation in the app that might touch the same data. For a backend, that's genuinely unusual.

The problem this solves shows up clearly in a collaborative project-management tool, a Linear or an Asana. Move one task from in progress to done, and a cascade kicks off: the project's percent-complete bar updates, a teammate's contribution count changes, the sprint burndown redraws, a Slack notification fires, and the activity feed gets a new entry. In a traditional architecture, a client talks to an app server backed by a database, a cache, a queue, and background workers. That one change fans out into a lot of places that all have to remember to react correctly.

Add a new status like "abandoned" later, and every one of those dependent calculations has to be found and updated by hand. It's easy to miss one, a cache invalidation here, a notifier there. As a codebase grows, remembering every place with an implicit dependency on a piece of state gets hard for a person and much harder for a model with a small context window.

Traditional backend versus ConvexTraditional backend versus Convex

This is a big part of why LLMs struggle with jQuery specifically. jQuery gave you convenient, standardized DOM manipulation, but it never managed state dependencies for you. You were always on the hook for wiring up what should update when something changed. That meant tracking a graph of dependencies by hand, across a codebase nobody could fully hold in their head, human or model. React's compositional design fixed that for the frontend once codebases got big enough that human working memory started to fail. LLMs hit that same wall much sooner than people do, so a system that removes the manual tracking helps them sooner, and more.

Trick three: minimizing the meta layer around race conditions

The third piece is more abstract, but it has the clearest practical bite. You know how to add any two numbers because you understand the underlying rules, the meta layer for how addition works, not because you memorized every combination. LLMs pick up meta-layer knowledge the same way, from patterns that are well represented in training data. A model plays checkers well because the moves and the strategy around checkers are all over its training data. Hand it a simple game you invented five minutes ago, and it's often much worse, because there's no meta-layer knowledge about that game to draw on.

Traditional backend engineering carries a big, mostly-invisible meta layer around consistency and race conditions, and LLMs are bad at it for two related reasons. First, the relevant state is usually split across independent systems: a cache here, a database there, each with its own mutation path. If a change in one system needs to invalidate or update the other, and that isn't handled atomically, you can end up reflecting only one of the two updates. Second, the strategies for avoiding that live almost entirely in engineers' heads rather than in public code or docs: ordering guarantees, what to check before a write, how to structure code so independently-owned systems stay consistent. It's operational knowledge concentrated at a handful of large companies, not something that shows up in the training corpus the way a syntax pattern does.

Convex sidesteps most of this by collapsing the pieces into one managed state graph instead of a collection of independently-owned systems. Convex's transaction protocol uses optimistic concurrency control. A mutation reads a consistent snapshot, and if something else wrote to the same data before it commits, Convex retries the mutation automatically instead of letting the two writes interleave unpredictably. Caching and invalidation happen automatically and stay consistent with the underlying data, so there's no separate cache-invalidation logic for an agent to get wrong in the first place.

That removes more than bugs. It wipes out an entire category of meta-layer knowledge that LLMs were never going to reach reliably. A rule set that lives in senior engineers' heads and postmortems isn't one an LLM can learn from training data, no matter how good the model gets.

The throughline

All three come back to the same comparison. Convex is agent-friendly for close to the same reasons React was people-friendly, and for close to the same reasons jQuery and classic distributed backends aren't.

Feedback works because everything is code, typed end-to-end, with no separate dashboard or config language sitting outside that type system, the way there is with React in a browser. Local reasoning works because the backend is reactive the same way a React component is, so an agent working on one function doesn't have to model the whole rest of the app to get it right. And minimizing the meta layer around consistency and race conditions means agents aren't leaning on tacit, undocumented expertise that was never going to show up in their training data.

What all three tricks do is narrow the job. They strip out the categories of knowledge agents were always going to be weakest at: project-specific context, cross-system dependency tracking, and distributed-systems folklore. In their place, agents get the one thing they're genuinely strong at, writing type-correct code and reacting to feedback until it compiles. That's why Convex agents punch above their weight. It doesn't make them good at everything, and it was never going to.

All gas, no breakages

Convex is the reactive backend platform that keeps up with you and your agents. Database, functions, workflow, sync, search, file storage, and more. All TypeScript, zero glue.

Get started