Substructure vs. Inngest for AI agents

Checked August 7, 2026

Inngest is for TypeScript teams who want durable background jobs of every kind: step functions with retries and checkpoints, plus AgentKit to assemble an agent inside your own app. Substructure is the assembled agent: config in git, running in Slack, with every step of the loop open to your code.

Both survive crashes. The difference is how much you assemble before anyone on your team can talk to an agent.

Use Inngest whenUse Substructure when
Agents are functions among many durable jobsThe agent is the product
You need concurrency keys, throttling, debounceYou need Slack, MCP auth, and approval
Your team is TypeScriptYour code is Go, Ruby, or anything on HTTP

What Substructure does that Inngest does not

  • Ships a working agent, not primitives. AgentKit gives you createAgent, createNetwork, routers, shared state, and MCP tool loading. The app that hosts them, the memory beyond one run, and the Slack app are yours.
  • Installs Slack in one command. Inngest has no Slack surface.
  • Holds the MCP credentials. In AgentKit, MCP auth is yours to build.
  • Asks a person as a feature. In AgentKit it is a documented pattern: a tool calls step.waitForEvent() and you build the surface that sends the resuming event.
  • Charges nothing per step. Inngest meters executions, a run plus every step, so an agent that thinks in many steps multiplies its own bill. Your compute bills separately, because Inngest never runs your code.

Side by side

Building the agent

InngestSubstructure
What you getDurable steps, plus AgentKitA running agent
LanguageTypeScript; AgentKit is pre-1.0Any language, over HTTP
Loop controlYours, in your appEvery step, over the wire
Human approvalstep.waitForEvent() plus a UIAn engine feature

Running it

InngestSubstructure
DurabilityCheckpointed stepsEvery step, before it runs
Who runs your codeYou do; Inngest orchestratesYou do, as one HTTP call
Flow controlConcurrency, throttle, debounce, priorityRetries and deadlines
Self-hostA binary, plus Postgres and Redis for multi-nodeOne binary and SQLite

Surfaces and price

InngestSubstructure
SlackYours to buildOne command
MCP authYoursThe engine's
StreamingRealtime, plus a React hookAG-UI, an open protocol
LicenceFair-source server; Apache SDKsOpen source
PriceMetered executions, steps includedFlat, bring your own key

What you write

agent.ts
const oncall = createAgent({
    name: "oncall",
    system: "You are the on-call assistant.",
    model: openai({ model: "gpt-5" }),
});
const network = createNetwork({ agents: [oncall] });
subs.toml
[worker.main]                          # optional: your code in the loop
url = "https://example.com/agent"

[agent.oncall]
llm = "openrouter"
model = "z-ai/glm-5.2"
system = "You are the on-call assistant."
mcp = [{ id = "sentry", tools = { read_only = true } }]
worker = "main"

[agent.oncall.slack]
name = "Oncall"

That worker line does more than it looks like. The engine sends every decision to the block's URL as JSON, and your endpoint can accept the step, change the prompt, use a different model, or run the tool in your own system.

Where Inngest is the better choice

  • Flow control. Per-key concurrency, throttling, debounce, and priority as one-line config, and nobody near it does this better.
  • One platform for billing pipelines, ETL, drip campaigns, and some agents.
  • step.ai.infer, which is the right shape for serverless economics.
  • AgentKit, if you want the whole agent as TypeScript in your own repo.

Questions

Is durability really different? Both save steps. Inngest orchestrates code you host; Substructure runs the agent loop itself and calls you when it needs a decision.

Can I keep Inngest for other jobs? Yes, and a worker can trigger Inngest functions.

What does it cost when the agents get busy? The same. There is no per-step or per-token charge.

The quick start takes about five minutes.