AI & ML · Oct 26, 2026 · 14 min read

Mastra vs LangChain for Production AI Agents (2026)

Mastra vs LangChain after the demo: durable state, evals, traces, deployment, cost, and human approval. The framework picker is a separate article.

Laptop on a dark desk showing Mastra and LangChain as two connected boxes

A demo that calls a model is not yet a production agent. This comparison is what happens to state, evals, traces, deploys, cost, and human approval when the process restarts. For the framework choice, including LlamaIndex, use the companion guide.

Start here if the demo already works

People searching Mastra vs LangChain, or LangChain vs Mastra, are often still choosing a framework. Language, ecosystem, and where LlamaIndex fits are the job of LangChain vs Mastra: Which Framework Fits in 2026?. This page starts one step later. You have an agent that works on your laptop. You need the run to survive a restart, a second server, a bad prompt change, and a tool call you do not want to run unattended.

The production questions are the same on both sides:

  • Where does the run's state live after the process exits?
  • How do you know a change made the agent better?
  • Can you see the model call, the tool call, and the tokens?
  • What do you deploy, and what has to be a database rather than RAM?
  • Which parts of the bill grow when the agent loops?
  • Where does a person approve, reject, or add the missing fact?

There is no scoreboard below. Both projects move quickly, and a number we did not measure would be fiction. The claims are the behaviors in the current docs, linked as we go. LangGraph is the stateful agent runtime in the LangChain ecosystem, documented for JavaScript and Python. Mastra is a TypeScript framework. The APIs differ. The failure you are avoiding is the same: a prototype that stored the conversation in memory, then lost it on the next deploy.

Orchestration: a graph, or an agent plus a workflow

Orchestration is the part that decides what runs next. The two projects put that decision in different objects.

LangGraph is a graph. The checkpointers guide describes a super-step as one tick in which every node scheduled for that step runs, possibly in parallel, and a checkpoint is saved at that boundary. You resume from a checkpoint, which is a super-step boundary, rather than from the middle of a node. If one node in a super-step fails, writes from the nodes that already finished are kept, and those successful nodes are not run again on resume. The orchestration model is nodes, edges, and a thread of checkpoints.

Mastra separates open-ended work from a fixed sequence. The agent overview says to use an agent when the steps are not known in advance: the model chooses the tools, how many times to loop, and when to stop. It says to use a workflow when the process is predetermined and the control flow is explicit. A workflow is where suspend() and resume() live. An agent can still pause one tool call for approval, which is a different gate from a workflow step. The platform overview describes the application as those three blocks: agents, tools, and workflows.

Use a graph when the path is a set of nodes you want to checkpoint, replay, and interrupt. Use an agent when the path is open-ended, and a workflow when you can name the steps. Many products need both. The production constraint is the same either way: the object that pauses has to be stored outside the process.

State that is still there after a restart

Both stacks will keep state in process memory if you let them. Both document that store as the wrong one for production.

LangGraph: a thread, a checkpoint, and an optional store

LangGraph's persistence guide splits memory in two. A checkpointer saves snapshots of graph state for one thread. That is the short-term memory: the conversation, a human-in-the-loop pause, time travel, and a place to resume after a failure. A store saves application data across threads, such as preferences and facts that should outlive one conversation. You pass a thread_id on the run. Reusing it loads that thread. A new id starts empty.

The in-memory saver is for experiments. The same guide says MemorySaver and InMemorySaver live in RAM and disappear when the process restarts. For a real service, compile the graph with a durable checkpointer. In the JavaScript library that is PostgresSaver: create it from a connection string and call setup() once so the checkpoint tables exist. The JavaScript persistence notes also say to keep thread_id under 255 characters in that Postgres saver, and to use a UUID when the natural key is longer.

How often a checkpoint is written is a separate choice. LangGraph.js documents three durability modes on the run. exit writes when the run finishes, errors, or hits a human interrupt. async writes in the background while the next step runs. sync writes before the next step starts. exit is the fastest, and it cannot recover a crash in the middle of a step. Durability modes apply to runs you execute yourself. If you run Agent Server, the persistence guide says you do not configure the checkpointer or the store in application code. The server handles that infrastructure for the deployment.

Mastra: memory, plus a workflow snapshot

Mastra splits the same problem across storage domains. The memory domain holds threads, messages, resources, and working memory. The workflows domain holds snapshots so a suspended workflow can resume. The docs say the default in-memory store is for tests and short local runs, and that it loses data when the process exits. The memory quickstart's LibSQL example uses :memory:, which has that same limit. Production means a persistent adapter. For memory, the storage guide points at a transactional database such as libSQL, PostgreSQL, or MongoDB.

On an agent, memory is addressed by a resource (the user or entity) and a thread (the conversation). Message history is on by default and can be capped to the last N messages. Three extra layers are optional. Working memory stores structured facts such as a name or a preference. Semantic recall pulls older messages by meaning rather than by recency. Observational memory, which the memory docs mark as the recommended path for long chats, uses background agents to compress older messages into an observation log so the raw transcript does not fill the context window. Turning it on requires a storage provider on the Mastra instance or on the agent.

A workflow pause is a different record from chat memory. When a step calls suspend(), Mastra writes a snapshot: step outputs, the path taken, which steps are suspended, and remaining retries. resume() loads that snapshot. The suspend-and-resume guide says those snapshots persist across restarts and deployments when storage is configured. Two Node processes that do not share that database cannot resume each other's runs.

Evals you can re-run after a prompt change

A production agent needs a test you can run again. A glance at the last demo is not that test. The two projects put the test in different places.

LangSmith evaluation is the LangChain path. Offline evaluation runs a dataset through the agent before you ship, then compares experiments. Online evaluation scores live traffic. The documented loop is: build a dataset from curated cases, old traces, or synthetic examples; score with a person, a code rule, an LLM-as-judge, or a pairwise comparison; run an experiment. In production, sample real runs and add the failures back to the dataset. A bug you saw once becomes a test you run the next time. The online steps say to use filters and sampling so live scoring does not have to score every request.

Mastra calls the same idea scorers. A scorer grades an agent output with a model, a rule, or a statistic, and returns a number that is typically between 0 and 1. You can supply your own prompt or scoring function. Live scorers run in the background and do not block the response. sampling.rate is the fraction of outputs that get scored, from 0 to 1. The docs say that choice is deterministic for a given trace id, so two scorers at the same rate see the same traces, and running the trace again makes the same sampling decision. Scores, datasets, and experiments are their own storage domains, and scorers can also sit in CI. When observability is not configured, that decision uses the run id instead. If trace sampling already declined the trace, scorers skip the run, so nothing is scored for a trace that was never stored.

Use either system as a gate on the change. A prompt edit with no dataset is a guess you cannot replay. The dataset can start small. It has to be a set of inputs you can run again.

Traces, not a single error line

An agent fails inside a sequence: the model chose a tool, the tool returned something unexpected, and the next model call continued. The stack trace of the HTTP handler does not show that sequence.

On the LangChain side, LangSmith is the trace store the eval product also reads. The checkpointer docs tell you to trace checkpointed state there so you can see how a run resumed across sessions. Offline and online evaluators both sit on those runs. If traces are not leaving the process, you also cannot promote a production failure into a dataset example, which is the loop the evaluation guide describes.

Mastra's observability docs record each agent run, workflow step, tool call, and model call as spans on a trace. The trace includes inputs, outputs, token usage, and timing. Metrics for latency, token usage, and cost are derived from those spans, without a second instrumentation pass. Set the top-level environment field so production and development traces stay separate. The tracing guide says a dev server resolves that field to development even when the process itself runs with NODE_ENV=production.

Where the spans are stored matters as soon as traffic is real. The observability overview treats telemetry as write-heavy and recommends a store that can take that load. MastraStorageExporter can write traces to ClickHouse, PostgreSQL, MSSQL, MongoDB, or LibSQL. The docs recommend ClickHouse when you keep observability yourself, DuckDB for local metrics, and MastraPlatformExporter when you want the hosted product. Composite storage sends the observability domain to one backend and memory to another. Studio can show traces on your machine. Decide how long production traces live, and keep secrets and raw customer payloads out of span attributes you did not mean to store.

What you actually deploy

The framework is a library until you pick a process and a database.

With LangGraph you have two shapes. You can run the graph inside your own service, compiled with a durable checkpointer and, when you need cross-thread memory, a store. Or you can run Agent Server, which injects the checkpointer and store configured for that deployment. Either shape still needs a real database behind it. An in-memory saver in a container that restarts on every deploy drops every paused approval and every conversation.

With Mastra, the docs say an application can run on any Node.js-compatible host, or on Mastra platform. The platform's Server product runs the app as an API. mastra deploy, or a connected GitHub repository, is the documented path. Studio is the hosted place to exercise agents and workflows, and Observability comes with those products. Hosted databases can be provisioned per environment, which is the durable storage the suspend-and-resume path needs. If you self-host, you bring that database. A container on the default in-memory store will answer a health check and forget the workflow snapshot on the next rollout.

Preview and production should use different databases for threads and checkpoints. A test resume that writes into the production checkpointer is a production run.

Cost follows the loop, not the logo

Your bill depends on the workflow you run. These are the drivers the docs name. They are not a vendor price list.

  • Context you resend. Message history that goes back to the model on every turn multiplies tokens. Mastra's observational memory replaces raw history with a shorter observation log as a chat grows. LangGraph checkpoints whatever you put in state, including a message list you never trim. Trimming, on that side, is your code.
  • Live scoring. A judged output is another model call, unless the scorer is pure code. Mastra's sampling.rate and LangSmith's sampling on online evaluators are the brakes. Score the risky tools and a sample of the rest. Widen the sample when you are changing the prompt.
  • Trace volume. Full inputs and outputs on every span are how you debug, and they are how an observability store grows. Mastra's guide treats that store as its own backend for that reason. Keep a retention window.
  • Unstopped loops. Mastra's agent overview says an agent iterates until the model stops or an optional stop condition is met. Set the condition. A tool that retries on a vague error will spend the budget you hoped to save with a cheaper model.

Watch token usage on traces you already collect. Mastra's metrics are derived from spans. LangSmith runs are the same kind of record on that side. A published average from someone else's agent is not your number.

A person can stop the action

Human-in-the-loop here means a pause that waits until someone answers, then a resume of the same run.

LangGraph does this with interrupt(). You call it inside a node with any JSON-serializable payload. The checkpointer saves the graph, the caller receives the payload, and the run waits until you invoke the graph again with a Command that carries the resume value. You use the same thread_id. JavaScript surfaces the payload on __interrupt__. Python's interrupts guide does the same for invoke(), and also exposes stream.interrupts when you stream events. Static breakpoints, which pause before or after a node, are documented as a debugging tool. Approvals belong in interrupt(). The interrupt needs a durable checkpointer. An in-memory saver holds the pause only until that process dies.

Mastra workflows use suspend() and resume(). The step returns suspend with a payload such as a reason, the run status becomes suspended, and you later call resume with the step id and resumeData that matches the step's resume schema. bail() stops the workflow when a person rejects the action. It does not raise. The run completes as a success and the later steps are skipped. When several steps each need a person, you resume them one at a time, in order. That resume works after a restart only if the snapshot was written to persistent storage.

Mastra agents have a second gate for tool calls. The agent human-in-the-loop guide pauses before execute when requireApproval is set on the tool, or requireToolApproval is set on that stream or generate call. The stream emits a tool-call-approval chunk with the tool name and arguments. You continue with approveToolCall or declineToolCall and the run id. A function can decide per call, for example only tools whose names start with delete_. Durable agents cannot store that function. The docs say a function in that context falls back to requiring approval. On the durable path, use a boolean and keep the policy in data you can serialize.

Put the pause on actions that are expensive or hard to undo: sending, deleting, paying, writing to a system of record. A gate on every lookup gets clicked through. The audit trail then says a person approved a call they did not read.

TypeScript and Python are different shipping surfaces

Language is part of what you ship, and it is a different question from where LlamaIndex fits. Retrieval over your own documents, and the three-way framework pick, stay on LangChain vs Mastra: Which Framework Fits in 2026?. This section is only the runtime you have to operate.

LangGraph documents the same production pieces for JavaScript and for Python: a checkpointer for one thread, a store across threads, and interrupt() for a pause. The caller-facing shape is not identical. JavaScript returns interrupt payloads on __interrupt__. Python's invoke() uses that same field, and stream_events with version="v3" also exposes stream.interrupts. A Python service and a TypeScript service can each compile a graph with a durable checkpointer. On the JavaScript side the database checkpointers are separate packages. The checkpointers guide lists @langchain/langgraph-checkpoint-postgres, plus SQLite, MongoDB, and Redis implementations, each installed on its own.

Mastra's agent and platform pages describe a TypeScript application on Node. The agent overview installs @mastra/core and says Node.js 22.18.0 and later can run the TypeScript entry file directly. Local work uses mastra dev. Production is a Node-compatible host you operate, or Mastra platform's Server, which the platform overview deploys with mastra deploy or a connected GitHub repository. Those pages do not document a Python SDK.

If the service that must call the tools is already Python, LangGraph is the documented runtime in that language. If the product is already TypeScript, Mastra keeps the agent, the workflow, memory, scorers, and traces in that process. LangGraph's JavaScript library inside that same service is also documented. Choose it when you want the graph and LangSmith, and you will operate the checkpointer, or Agent Server, yourself.

How to choose once production is the question

Stay with LangGraph when the team already runs LangSmith, or is ready to, and the agent is a graph you want to checkpoint, interrupt, and score as experiments. You will either operate Agent Server or compile the graph yourself with a database checkpointer. Python and JavaScript are both documented. Use the language the service is already written in.

Stay with Mastra when the product is TypeScript and you want agents, workflow suspend and resume, memory, scorers, and traces in one framework, deployed as a Node process or on Mastra platform. The setup that has to be true on day one is persistent storage for memory and workflow snapshots, plus an observability exporter other than the in-memory default. That is the production work behind our AI solutions practice: one workflow, a store that survives a restart, and a trace you can read.

If you are still choosing the language, or the real job is retrieval over your own documents, use the framework picker. LlamaIndex belongs on that page, because that page is about what the system is for. This one is about checkpoints, traces, and approval gates.

One workflow, measured

The useful next step is one workflow you already run, on data you already have, against a metric you already collect. The 2-Week AI Agent Pilot instruments that workflow before the demo, records a run on your data, and writes the before-and-after on the metric you agree up front. An optional monthly retainer can follow.

Bring the failure you care about. A restart that loses the thread. A tool call that should have waited. A prompt change you cannot tell improved anything. Tell us about that workflow and we will scope the 2-Week AI Agent Pilot around it.

← Back to blog

Fixed price

Send the repo. Get a quote.

Tell us if you need an MVP Rescue Audit, a 30-day web, mobile, or SaaS sprint, or a 2-week AI agent pilot. The price is in the quote.