LangGraph alternatives, honestly compared
Who should stay on LangGraph and who wants Mastra, Pydantic AI, a provider SDK or a platform, compared on loop ownership, state, tenancy, surfaces and evals.
Stay on LangGraph if you want to own the agent loop as an explicit state machine with checkpoints, interrupts and time travel, in Python or TypeScript. Move to Mastra or Pydantic AI if you want a framework that runs the loop for you with typed outputs and evals included. Reach for a provider SDK when you are committed to one vendor and want the shortest path to a working agent. Add a platform such as Runtype around the graph when the agent is customer-facing and multi-tenant, and you would rather have tenancy, approvals, evals and surfaces handled than write them.
Most people searching for LangGraph alternatives are not unhappy with the graph. They are unhappy with everything around it: the chat UI, the Slack integration, the per-customer isolation, the eval loop, the cost report per tenant. That is a product-layer problem, and no library solves it.
Who should stay on LangGraph
Stay on LangGraph when the orchestration itself is the product: you want to write the loop, not configure it, as an explicit graph with nodes you can name, edges you can draw, and a typed state every node reads and writes. LangGraph is the only option on this page where that is the entire design.
Three capabilities are specific to LangGraph and hard to reproduce without building them yourself:
- Checkpointing as a first-class object. Every super-step writes the full state to a checkpointer (in-memory, SQLite, or Postgres), keyed by a
thread_id. Crash recovery, pausing, and resuming a week later all fall out of that one mechanism. - Interrupts you resume with a value.
interrupt()stops the graph mid-node, surfaces a payload to the caller, andCommand(resume=...)feeds the human's answer back in. Approval, clarification and editing a draft all use the same primitive. - Time travel. Because checkpoints are a history, you can fetch an earlier state, fork it, and rerun the graph from there. That is how you replay a bad run with a corrected tool result rather than starting over.
from langgraph.graph import StateGraph, START, END
from langgraph.checkpoint.memory import InMemorySaver
from langgraph.types import interrupt, Command
from typing_extensions import TypedDict
class State(TypedDict):
draft: str
approved: bool
def write(state: State) -> State:
return {"draft": "Refund of $42 approved for order 1187", "approved": False}
def review(state: State) -> State:
decision = interrupt({"draft": state["draft"]})
return {"approved": decision == "approve"}
graph = (
StateGraph(State)
.add_node("write", write)
.add_node("review", review)
.add_edge(START, "write")
.add_edge("write", "review")
.add_edge("review", END)
.compile(checkpointer=InMemorySaver())
)
config = {"configurable": {"thread_id": "order-1187"}}
graph.invoke({"draft": "", "approved": False}, config) # stops at review
graph.invoke(Command(resume="approve"), config) # resumes from the checkpoint
If that snippet is exactly the level of control you want, you do not need an alternative. You need the things around it, which the last two sections cover.
Comparison table
Every cell describes what ships with the tool itself, not what you could build on it. "Provider SDKs" covers the OpenAI Agents SDK, Anthropic's Claude Agent SDK and the Vercel AI SDK; where they differ, the cell says which.
| Dimension | LangGraph | Mastra | Pydantic AI | Provider SDKs | Runtype |
|---|---|---|---|---|---|
| What it is | Graph orchestration library | TypeScript agent framework | Python agent framework | Vendor SDKs with a thin agent loop | Platform: hosted or self-hosted runtime |
| Language | Python, JavaScript/TypeScript | TypeScript | Python | OpenAI: Python and TypeScript. Claude: Python and TypeScript. Vercel: TypeScript | Configured, not coded: REST API and SDKs |
| How much of the loop you own | All of it: you define nodes, edges and state | Agents run a built-in loop; workflows are steps you write | Built-in loop with typed hooks; Pydantic Graph if you want an explicit state machine | The SDK's loop; you supply tools, prompts and stop conditions | Yours if you keep it (registered over A2A or a streaming endpoint), or the platform's, with caps on turns and tool calls |
| State and durability | Checkpointers (memory, SQLite, Postgres), interrupts, time travel over checkpoint history | Workflow suspend and resume; memory with pluggable storage | Optional durable execution through Temporal, DBOS, Prefect or Restate integrations | OpenAI: sessions. Claude: resumable sessions. Vercel: none built in, you persist messages | Durable turns with a run handle; async execution returns 202 and a status URL; watch leases detach without aborting the run |
| Multi-tenancy and end-user identity | Not built in; thread_id is a string you namespace yourself | Not built in; memory is keyed by the resource and thread you supply | Not built in; dependency injection is where you would pass a tenant | Not built in | Tenancy strategy per resource (internal, tenant-isolated, end-user-isolated) with an assurance floor of asserted or verified; requests below the floor are rejected |
| Surfaces (chat, Slack, API, MCP) | None in the library; LangSmith Deployment exposes an API; UI is yours | Local playground and API routes; production UI is yours | None; you expose the agent yourself | Vercel: useChat hooks for your own UI. OpenAI and Claude: UI is yours | One agent behind many surfaces: web chat, Slack, REST API, SMS, iMessage, MCP server, A2A, schedules |
| Evals | Through LangSmith (separate product) | Built-in scorers | Pydantic Evals (separate package) | OpenAI: evals in the OpenAI platform. Claude and Vercel: none in the SDK | Suites and cases, LLM-judge scoring with human review, coverage reporting, production failures captured as regression cases |
| Observability | LangSmith tracing, or OpenTelemetry | Tracing in the playground; OpenTelemetry exporters | Logfire, or OpenTelemetry | OpenAI: traces dashboard. Claude: hooks. Vercel: OpenTelemetry | Per-step traces, cost per execution, record and batch, cached versus uncached tokens, OTLP ingest from external agents |
| Hosting | Self-host, or LangSmith Deployment | Self-host on Node or serverless through deployers, or the hosted Mastra platform | Self-host anywhere Python runs | Anywhere the language runs; models are vendor-tied (Vercel excepted) | Managed cloud, or self-hosted on your own infrastructure with the same product definition |
LangGraph: the graph library
LangGraph is best at long-running, branching, resumable control flow where you can name every state and transition. Multi-step research agents, approval workflows with several human touchpoints, and anything where "rerun from step four with a fix" is a requirement all fit it. Its persistence model is the most complete on this page, and its streaming modes (values, updates, messages, custom) control what the caller sees mid-run.
Choose it if you are a Python or TypeScript team that wants low-level control and is prepared to build the product layer, or to buy it from LangSmith. LangSmith gives you tracing, evals and prompt management; LangSmith Deployment, the renamed LangGraph Platform, hosts the graph behind an API with threads and background runs. Both are separate products with their own pricing, and as of September 2026 running the deployment control plane on your own infrastructure is an Enterprise-plan option.
Its honest limitation is that the library is the whole offer. There is no notion of a tenant, an end user, a surface or an approver inside LangGraph; thread_id is a string, and isolation is whatever your code enforces. There is also ceremony: a two-tool assistant is a graph with a state schema, a checkpointer and an edge list, a state machine you are not using.
Mastra: a TypeScript framework with the product pieces included
Mastra is best for TypeScript teams who want agents, workflows, memory, RAG and evals from one package, with a local playground that lets you talk to the agent, inspect traces and run workflows before you deploy anything. The framework runs the loop for you: you define an agent with instructions, a model and tools, and call generate or stream. Workflows are typed steps with branching, parallel execution and suspend and resume, which covers most of what people use LangGraph interrupts for.
import { Agent } from '@mastra/core/agent'
import { openai } from '@ai-sdk/openai'
import { lookupInvoice } from './tools'
export const billingAgent = new Agent({
name: 'billing',
instructions: 'Answer billing questions. Call lookupInvoice before quoting any number.',
model: openai('gpt-4o'),
tools: { lookupInvoice },
})
Choose it if you are on Node or a serverless JavaScript runtime and want the shortest path from "agent in a file" to "agent with memory, evals and traces". Its evals are scorers you attach to an agent and run over outputs, enough to catch regressions in CI. Deployment adapters exist for Vercel, Cloudflare and Netlify, plus the hosted Mastra platform.
Its honest limitation is that it is still a framework: the UI, the Slack app, the per-customer isolation and the approval surface are yours to build, and memory expects you to pass a resource and a thread rather than knowing who the end user is. It is also TypeScript only.
Pydantic AI: Python with types as the contract
Pydantic AI is best for Python teams that already trust Pydantic and want the same guarantees on model output. You declare an output_type, and the agent retries until the model produces something that validates; you declare a deps_type, and every tool receives it through RunContext. That dependency injection is the cleanest place on this page to thread a tenant id, a database handle or a feature flag into every tool call without global state.
from dataclasses import dataclass
from pydantic import BaseModel
from pydantic_ai import Agent, RunContext
@dataclass
class Deps:
tenant_id: str
db: "OrdersDb"
class RefundDecision(BaseModel):
approve: bool
amount_cents: int
reason: str
agent = Agent("openai:gpt-4o", deps_type=Deps, output_type=RefundDecision)
@agent.tool
async def order_total(ctx: RunContext[Deps], order_id: str) -> int:
return await ctx.deps.db.order_total(ctx.deps.tenant_id, order_id)
result = await agent.run("Should we refund order 1187?", deps=Deps(tenant_id="acme", db=db))
print(result.output.amount_cents) # an int, validated
Choose it if you value type safety over ceremony and want to stay model-agnostic; it speaks to OpenAI, Anthropic, Google, Groq, Mistral, Bedrock and others behind one interface. Pydantic Graph gives you an explicit state machine when you need one, Pydantic Evals covers scoring, and Logfire or plain OpenTelemetry covers tracing. Durable execution comes through integrations rather than a built-in checkpointer.
Its honest limitation is the same shape as Mastra's: a clean agent and a clean place to inject a tenant, and nothing that knows what a tenant is. Surfaces, approvals and cost per customer are yours to write. It is also Python only.
Provider SDKs: OpenAI Agents SDK, Claude Agent SDK, Vercel AI SDK
The provider SDKs are best at getting a working agent in an afternoon, with the vendor's newest features available the day they ship. They are thin on purpose: a loop, tool calling and streaming, and then they stop.
OpenAI Agents SDK (Python and TypeScript) adds handoffs between agents, input and output guardrails, sessions for conversation memory, and tracing into the OpenAI dashboard. Tool calls can be marked as needing approval (needs_approval in Python, needsApproval in TypeScript), which pauses the run until you resume it. It works best against the Responses API; in Python, LiteLLM reaches other providers, minus the OpenAI-specific features.
Claude Agent SDK (Python and TypeScript) is the harness behind Claude Code, exposed as a library: built-in file, shell and web tools, subagents, hooks before and after tool calls, MCP server support, permission modes, and resumable sessions. It is the right pick for an agent that operates over a filesystem or codebase. It runs Claude models only, through the Anthropic API, Bedrock or Vertex.
Vercel AI SDK (TypeScript) is the most portable of the three: one streamText call, dozens of providers, tools defined with a schema, and a stop condition that turns a single call into a loop. Its useChat hooks are the fastest way to a streaming chat UI in React, and version 7's ToolLoopAgent class wraps the same loop for reuse.
import { streamText, tool, isStepCount } from 'ai'
import { openai } from '@ai-sdk/openai'
import { z } from 'zod'
const result = streamText({
model: openai('gpt-4o'),
system: 'You answer billing questions for one customer at a time.',
messages,
tools: {
lookupInvoice: tool({
description: 'Fetch an invoice by id',
inputSchema: z.object({ invoiceId: z.string() }),
execute: async ({ invoiceId }) => db.invoices.get(invoiceId),
}),
},
stopWhen: isStepCount(8),
})
Choose a provider SDK if one vendor is fine (or, with the Vercel AI SDK, you are already on Next.js), the tool set is small, and the users are on your team. Their honest limitation is vendor or runtime lock: the OpenAI and Claude SDKs tie you to a model family, the Vercel SDK to a JavaScript runtime, and none has an answer for durability, tenancy, evals or surfaces beyond what the vendor's dashboard offers.
How to choose in four questions
Answer these in order. The first "yes" is usually the decision.
- Is the orchestration graph itself the thing you are selling or differentiating on? Stay on LangGraph.
- Are you in one language and want the loop run for you, with typed outputs and evals included? Mastra for TypeScript, Pydantic AI for Python.
- Is one vendor fine, the tool set small, and the users internal? The matching provider SDK.
- Will your customers, in their own accounts, use this agent through a UI or channel you do not want to build? You are looking for a platform, not a library, and the rest of this page is about that.
The question none of them answer
Every option above assumes an agent your team runs: one deployment, one set of credentials, users who are your own employees, and failures you read in a terminal. That is reasonable for an internal tool. It stops being reasonable the day the agent is embedded in your product and your customers use it.
Four things change, and none of them is an orchestration problem:
- Identity has two layers. The request comes from your customer's end user, inside your customer's account, inside your product. A
thread_idstring does not carry that, and a prompt that says "you are talking to Acme" is not isolation. Something has to verify who is asking before the run starts. - Approvals need an approver who is not you. When the agent wants to issue a refund for a customer, the person who should approve it works at the customer. That approver needs a surface, a timeout and a durable record of the decision.
- Cost becomes a per-tenant number. One customer's chatty users can consume the budget of ten quiet ones. You need spend attributed to the tenant and the end user, not one monthly bill.
- Evals run against real traffic. The failures that matter are the ones a customer hit yesterday. Turning a production run into a regression case and rerunning the suite against a candidate model is a workflow, not a script.
LangGraph, Mastra, Pydantic AI and the provider SDKs leave every one of those to you. That is a statement of scope, not a flaw. It is also why many "LangGraph alternatives" searches end at a platform rather than another library.
Where Runtype fits
Runtype is the product layer the graph is missing, and the graph keeps running where it is. Four ways in, in the order most teams take them.
- Register the agent. Keep the LangGraph graph and give it an endpoint that speaks Runtype's unified stream or A2A, then create an
externalagent pointing at it. Runtype calls the graph: testable from the dashboard, MCP or the SDK, embeddable in the open-source Persona chat widget, added to a product as a capability behind every surface in the table above, and put on schedules. Tool calls and cost are recorded per run. - Serve it tools. Point it the other way. An MCP surface exposes a product's flows, agents, records, skills and tools as MCP tools, so the graph stays the orchestrator and calls Runtype for the parts worth centralizing. Nothing about the graph changes.
- Send traces. LangGraph's OpenTelemetry export can go to
https://api.runtype.com/v1/otelfor the Runs view, the trace tree and token usage. Spans carrying the GenAI content attributes give you a transcript you can capture as an eval case, and pointing two instrumentations at the endpoint doubles tokens and cost. - Rebuild when it earns it. Port one node at a time to a Runtype flow or hosted agent, once the suite harvested from real runs proves parity for that node. A rebuilt capability is versioned, published and gated:
runtype eval runreturns a non-zero exit code on a regression in CI.
Identity is a declared property of each resource: a tenancy strategy of internal, tenant-isolated or end-user-isolated with an assurance floor of asserted or verified, evaluated before execution, so a request below the floor never reaches the graph. thread_id stays a string in your code, and the boundary is enforced outside it. Every trace and cost figure is filed under the tenant and end user the request ran for (end-user identity).
Approval gates cover all tools or a named list, with a five-minute default timeout, persistent always-allow or always-deny grants, and an approver at your customer who can answer from Slack. The agent's stated reason reaches that approver as the agent's claim and never as a control signal.
Eval suites turn a production failure into a regression case from its recorded run, score it with an LLM judge under human review, and can run against a candidate model before you switch. Cost lands per execution, record and batch with cached and uncached token counts. It runs on the managed cloud or self-hosted on your own infrastructure. The graph you already trust can stay exactly where it is.
Frequently asked questions
- Is LangGraph a framework or a library?
- It is a library. LangGraph gives you a graph of nodes and edges over a typed state, plus checkpointing, interrupts and streaming, and leaves the UI, hosting, evals and tenancy to you. LangSmith and LangSmith Deployment are the separate products that fill some of those gaps.
- Which LangGraph alternative is closest in spirit?
- Pydantic Graph, which ships alongside Pydantic AI, is the closest Python match because it is also an explicit state machine with typed state. In TypeScript, Mastra workflows cover branching, parallel steps and suspend and resume, but as a step pipeline rather than an arbitrary graph.
- Do I lose human-in-the-loop if I leave LangGraph?
- Not necessarily, but it changes shape. LangGraph exposes it as an interrupt you resume with a Command, Mastra workflows suspend at a step, and the OpenAI Agents SDK and Vercel AI SDK gate individual tool calls. A platform moves the gate out of your code into a policy on the tool, with a timeout and an approver surface.
- Can I keep LangGraph for orchestration and add a platform around it?
- Yes, and it is the common shape when the graph already works. You keep the graph as the brain, export its traces over OpenTelemetry, and let something else own tenant identity, approvals, surfaces and evals. Runtype accepts OTLP traces from agents running elsewhere and can register an external agent behind surfaces, schedules and eval suites.
- When is a provider SDK enough?
- When one vendor is fine, the agent has a handful of tools, and its users are on your team. The OpenAI Agents SDK, Claude Agent SDK and Vercel AI SDK all get a working tool loop in an afternoon. They stop fitting when you must swap models under a contract, isolate customers from each other, or hand one agent to Slack, a widget and an API at once.