Best LangGraph Deployment Platforms in 2026
The LangGraph demo always works. Four nodes, a state schema, a notebook, and an agent that reasons its way to a plausible answer. Then someone asks where it runs, and the question stops being about graphs. A LangGraph agent in production is a long-lived, stateful, interruptible process with a database it cannot lose, a streaming connection to a UI, and a tool that runs code the model just made up. Most deployment targets are the wrong shape for that.
So this roundup starts with requirements rather than vendors, because the requirements do most of the eliminating for you. Write them down and half the platforms you were considering disqualify themselves in a sentence; what's left is mostly a question of how much operations you want to own. I founded PandaStack, which appears in the field below, so weight this accordingly — I keep it honest by citing specific numbers only for our own system, describing everything third-party qualitatively, and telling you to verify anything load-bearing against the vendor's current docs, because limits and pricing change monthly.
The six requirements that eliminate most platforms
Each of these is a real property of how LangGraph works, not a nice-to-have, and each one rules out a category of hosting.
- Durable, long-running execution — a graph is not a request. One invocation can run for minutes across a dozen model calls, or park for days on a human-in-the-loop interrupt. Anything with a hard request timeout is fighting your framework, and it will win.
- A checkpointer backed by a real database — the whole value of the framework is that state survives a crash, a restart, and a deploy. Postgres is the common answer. In-memory checkpointing is a development convenience that turns every restart into silent data loss.
- Human-in-the-loop pauses that don't bill — an approval-gated graph is idle far more than it is running. If your platform charges for a warm container while a reviewer sleeps, you are renting a machine to wait. Scale-to-zero plus a fast wake matters more here than raw throughput.
- Streaming to a UI — token streaming and intermediate step events mean the transport has to hold a connection open for the life of the run. Check how a platform treats SSE and WebSockets specifically, not just 'HTTP'.
- A code-execution sandbox for tool calls — the graph will eventually call a tool that runs model-written Python, and that must not execute in your API process. Most LangGraph deployment guides skip this, which is how you end up with subprocess.run in a web worker.
- Observability and replay — when someone asks why run #4471 did that, you need the whole trajectory: node transitions, tool calls, checkpoints, and ideally the ability to resume from a checkpoint and watch it happen again.
The requirement everyone skips
Requirements one through four are runtime properties, and every serious platform has an answer. The fifth is different, because it gets decided by accident. An agent that can run code is dramatically more capable than one that can't, so you add the tool. The tool is thirty lines. Those thirty lines usually call subprocess inside the same process that holds your Postgres connection string, your model API keys, and your customer data.
The model isn't malicious; it's confident. It will write a cleanup script with a variable that resolves to an empty string, and the resulting path will be the root of whatever filesystem it is standing on. Prompt injection makes it worse: anything the agent reads from the web or a user document is an instruction channel into your tool loop. The fix is boring — tool execution belongs in a disposable environment with its own kernel and no ambient credentials, created and destroyed per call.
First, wire a real checkpointer
Get this right before you evaluate hosts, because it determines what you need from one. A Postgres-backed checkpointer is what makes a run resumable: state is persisted at every super-step against a thread_id, so a crash mid-run, a rolling deploy, and a three-day human approval all resolve to the same operation — reload the thread and continue.
import os
import operator
from typing import Annotated, TypedDict
from langgraph.graph import StateGraph, START, END
from langgraph.checkpoint.postgres import PostgresSaver
class State(TypedDict):
messages: Annotated[list, operator.add]
approved: bool
def plan(state: State) -> dict:
# ... call the model, decide what to do next ...
return {"messages": [{"role": "assistant", "content": "drafted a plan"}]}
def act(state: State) -> dict:
# ... execute tools, write results back into state ...
return {"messages": [{"role": "tool", "content": "done"}]}
# A durable Postgres -- NOT an in-memory saver. This database is the
# agent's memory; treat it like production data, because it is.
DB_URI = os.environ["CHECKPOINT_DB_URL"] # postgresql://user:pw@host:5432/agent
with PostgresSaver.from_conn_string(DB_URI) as checkpointer:
checkpointer.setup() # idempotent; creates the checkpoint tables once
builder = StateGraph(State)
builder.add_node("plan", plan)
builder.add_node("act", act)
builder.add_edge(START, "plan")
builder.add_edge("plan", "act")
builder.add_edge("act", END)
# Checkpointing is a compile-time concern, not a runtime flag.
graph = builder.compile(checkpointer=checkpointer, interrupt_before=["act"])
# A thread_id is the durable identity of one run.
config = {"configurable": {"thread_id": "run-4471"}}
for event in graph.stream({"messages": [], "approved": False},
config=config, stream_mode="values"):
print(event)
# Three days later a human approves. Different process, different host,
# possibly a different deploy -- same thread_id, and the graph resumes
# from the checkpoint instead of starting over.
graph.invoke(None, config=config)Notice what the last line implies about hosting: the process that resumes a run does not have to be the process that started it. If the checkpointer is durable, the compute can be disposable — and that's the property that makes scale-to-zero hosting viable for agents instead of terrifying.
The field: seven places to run it
Each option gets what it is, who it's for, and where it hurts. No invented prices, latencies, or limits for anyone but us — verify against current docs, because all of these ship changes faster than roundups get updated.
1. LangGraph's own managed platform
The path of least resistance: durable execution, checkpointing, streaming, interrupts, and tracing are designed together by the people who wrote the framework rather than assembled by you. If your main risk is getting the runtime semantics subtly wrong, buying the runtime from its authors removes that risk in an afternoon.
- Who it's for — teams who want the framework's own semantics with the least assembly, and who value time-to-production over control of the substrate. Verify current tiers, self-hosted options, and pricing against LangChain's docs.
- Where it hurts — it's the most opinionated box in the lineup: you inherit their runtime, scaling model, and roadmap. And the tool sandbox is still yours, because a managed graph runtime is not a managed place to run model-written code.
2. Self-hosting the server on Kubernetes
Run the LangGraph server in your own cluster, with your own Postgres and ingress. This is the answer when the target is dictated by compliance, data residency, or a platform team that already runs everything this way. Long-running work is fine — a Deployment doesn't care how long a request takes, as long as your ingress and load balancer timeouts agree with you, which is the first thing to check and the thing people forget.
- Who it's for — organizations that already operate Kubernetes competently and need the agent inside an existing security and networking perimeter.
- Where it hurts — idle cost and ops burden. Pods don't scale to zero without extra machinery, so an approval-gated agent bills replicas for waiting. You also own upgrades, connection pooling, autoscaling against a workload whose CPU profile is 'occasionally', and the sandbox question all over again.
3. Container app platforms (Railway / Render-style)
Push a repo, get a container with a URL and a managed Postgres next to it. For a small team shipping their first production agent this is hard to beat on effort-to-outcome: the checkpointer database is one click, and streaming generally works because these platforms exist to run long-lived web processes.
- Who it's for — small teams who want a managed Postgres and a running container without hiring for infrastructure, with graphs that run for minutes rather than days.
- Where it hurts — sleep behavior and request timeout limits vary by platform and plan, so verify both; a container that never sleeps means idle billing dominates a human-in-the-loop workload. Tool code also runs in your app container by default, which is exactly the arrangement you're trying to avoid.
4. Fly.io
Fly Machines are fast-booting, API-driven VMs you can start, stop, and scale to zero, with persistent volumes. That shape maps unusually well onto agents: a machine per long-running graph, stopped while nothing is happening, woken when the human finally clicks approve. It's also programmable, which matters if you want a machine per tenant or per run instead of one shared web service.
- Who it's for — teams who want scale-to-zero idle cost with the freedom of a VM, and are comfortable orchestrating machines through an API rather than pushing to a git-driven PaaS.
- Where it hurts — you assemble the agent platform yourself from good primitives: wake logic, routing to the right machine, checkpointer provisioning, and observability are on you. Confirm current scale-to-zero, volume, and managed-Postgres offerings against Fly's docs, since that posture has shifted over time.
5. AWS ECS / Fargate with a managed Postgres
The enterprise default: a long-running service on Fargate, RDS or Aurora for the checkpointer, a load balancer in front, IAM and VPC around it, all inside the account your security team already reviewed. It clears every requirement on the list because it's general-purpose compute — the answer to 'does it support X' is always 'yes, with configuration'.
- Who it's for — teams already deep in AWS, where compliance and networking matter more than iteration speed and the agent has to sit beside existing services.
- Where it hurts — ceremony and idle cost. Warm tasks bill while the graph waits on a human, load-balancer idle timeouts need explicit attention for streaming responses, and going from a working graph to a deployed one involves real Terraform. Verify current timeout and streaming defaults against AWS docs; they will surprise you.
6. Serverless functions (and why they mostly don't fit)
This is the option people want to work, so it deserves an explanation rather than a dismissal. Functions are cheap when idle, scale instantly, and need no ops — a great match for requirement three and nothing else. The mismatch is structural: they have maximum execution durations, and a graph spanning many model calls or waiting on an interrupt does not respect them. Streaming from a function exists on several platforms, but as a constrained feature rather than a default — verify per platform. And the stateless invocation model makes every step pay checkpointer round-trips against a database functions are historically bad at pooling connections to.
- Who it's for — genuinely short, stateless graphs: a classify-and-route flow, a single-tool lookup, or the webhook that receives an approval and enqueues a resume. Functions are excellent glue around an agent.
- Where it hurts — as the agent runtime itself. You end up decomposing the graph across invocations, reimplementing durable execution on a queue, and rediscovering why LangGraph has a checkpointer. If you're going to build a durable state machine on functions, use a workflow engine designed for it.
7. PandaStack
Our project, so weight it accordingly — but the shape is a direct answer to the six requirements. The graph runs in a long-lived Firecracker microVM with its own guest kernel, so it isn't a request and has no timeout to violate. The checkpointer is a managed Postgres that is itself a microVM on the same substrate (create runs 30–90s), so the agent and its memory are provisioned together instead of being two vendor relationships. Between interrupts the agent's VM hibernates to a snapshot and comes back on demand — restores land at 179ms p50 and roughly 203ms p99, the restore step itself around 49ms — which is what makes 'idle for three days' cost like idle rather than like uptime. Only the first boot of a fresh template is slow, around 3s.
The agent-specific part is the tool call. Each execution of model-written code gets its own Firecracker microVM with its own kernel, rootfs, and network namespace, created for the call and destroyed after. When the model writes an enthusiastic rm -rf, it deletes a filesystem that exists to be deleted, in somebody else's kernel. Copy-on-write forking (400–750ms same-host, 1.2–3.5s cross-host) also lets you warm a sandbox once — dependencies installed, dataset loaded — and fork it per call instead of rebuilding it every time.
- Who it's for — long-running, interrupt-heavy agents where you want the graph, its Postgres checkpointer, and per-call code isolation on one substrate, with the option to self-host on your own KVM hosts.
- Where it hurts — it isn't a first-party LangGraph runtime, so you wire the server or your own loop rather than inheriting framework-authored deployment semantics. And if your agent never runs generated code and never idles, you're buying isolation and scale-to-zero you don't need — a container PaaS is the better call.
The comparison, dimension by dimension
Find the row forcing your decision, then read only the two options that clear it. Third-party behavior here is qualitative and changes — this is a shortlist tool, not a spec sheet.
- Long-running executions — LangGraph Platform: designed for it. Kubernetes: fine once ingress timeouts agree. Container PaaS: usually fine, check plan limits. Fly.io: fine — VMs, not requests. ECS/Fargate: fine, mind the load-balancer timeout. Serverless: hard ceiling, the core mismatch. PandaStack: a long-lived microVM with no request semantics at all.
- Human-in-the-loop idle cost — LangGraph Platform: tier-dependent, verify. Kubernetes: you pay for warm replicas. Container PaaS: plan-dependent sleep behavior. Fly.io: strong — machines stop and scale to zero. ECS/Fargate: warm tasks bill while you wait. Serverless: near-zero idle, its one real win. PandaStack: hibernate to snapshot between interrupts, wake on the restore path.
- Checkpointer Postgres included — LangGraph Platform: managed as part of the product. Kubernetes: bring your own. Container PaaS: yes, usually one click. Fly.io: in-ecosystem, verify current offering. ECS/Fargate: RDS or Aurora, separately provisioned. Serverless: bring your own and mind pooling. PandaStack: managed Postgres microVM on the same substrate.
- Streaming support — LangGraph Platform: first-class. Kubernetes: yes, configure ingress buffering. Container PaaS: generally yes. Fly.io: yes. ECS/Fargate: yes, with timeout tuning. Serverless: platform-specific and constrained, verify. PandaStack: a long-lived VM holding an open connection, no special case.
- Tool-call code isolation — LangGraph Platform: not included, bring a sandbox. Kubernetes: shared host kernel unless you add gVisor or Kata. Container PaaS: runs in your app container by default. Fly.io: strong primitive, but you orchestrate a VM per call. ECS/Fargate: task-level, not per-call. Serverless: per-invocation, but timeouts cap what a tool can do. PandaStack: a fresh Firecracker microVM per tool call.
- Ops burden — LangGraph Platform: lowest. Kubernetes: highest. Container PaaS: very low. Fly.io: moderate — good primitives, you assemble. ECS/Fargate: high (IAM, VPC, Terraform). Serverless: low to run, high to make durable. PandaStack: low managed, moderate self-hosted.
Wiring the tool sandbox
Whichever host you pick, this piece stays yours. The shape: a tool that creates a disposable microVM, writes the model's code into it, runs it under a timeout, returns the three things the model needs — stdout, stderr, exit code — and destroys the environment on the way out.
import json
from langchain_core.tools import tool
from langgraph.prebuilt import ToolNode
from pandastack import Sandbox
@tool
def run_python(code: str) -> str:
"""Execute Python code and return its stdout, stderr, and exit code.
The code runs in a disposable, isolated microVM. Use it for calculations,
data manipulation, and file work. State is NOT preserved between calls --
every call gets a fresh machine.
"""
# A fresh Firecracker microVM per tool call: own guest kernel, own rootfs,
# own network namespace, none of this process's credentials.
# ttl_seconds is a backstop in case the context manager never unwinds.
with Sandbox.create(template="code-interpreter", ttl_seconds=300) as sbx:
sbx.filesystem.write("/workspace/cell.py", code)
r = sbx.exec("python3 /workspace/cell.py", timeout_seconds=60)
# Truncate before this re-enters the context window -- a runaway print
# loop should cost you tokens, not your entire prompt budget.
return json.dumps({
"exit_code": r.exit_code,
"stdout": r.stdout[-4000:],
"stderr": r.stderr[-2000:],
"duration_ms": r.duration_ms,
})
# VM destroyed here. Whatever the model did to that filesystem is gone.
# Bind it like any other LangChain tool, then hang it off the graph.
tools = [run_python]
tool_node = ToolNode(tools)
model_with_tools = llm.bind_tools(tools) # llm = your chat model
# builder.add_node("tools", tool_node)
# builder.add_conditional_edges("plan", tools_condition)
# builder.add_edge("tools", "plan")Two details worth stealing regardless of vendor. Truncate output before it re-enters the context window, because an accidental infinite print loop will otherwise consume your prompt budget in a single tool call. And return the exit code explicitly — models self-correct far better from a non-zero exit plus a stderr tail than from a polite 'something went wrong'.
How to choose
Work down this list and stop at the first line that describes you. The requirement forcing your hand usually picks the platform for you.
- You want the framework's own semantics with the least assembly — take LangGraph's managed platform and revisit when a specific limit hurts.
- Your target is dictated by compliance, data residency, or an existing platform team — self-host on Kubernetes and budget for always-warm replicas.
- You're a small team shipping your first production agent and runs finish in minutes — a container PaaS with one-click Postgres gets you live this week; add a real sandbox before you enable code execution.
- You're already deep in AWS and the agent must sit beside existing services — ECS/Fargate plus RDS, with explicit attention to load-balancer idle timeouts for streaming.
- Your agent idles far more than it runs and idle cost is the number that hurts — pick scale-to-zero compute: Fly Machines to assemble it from primitives, PandaStack for the graph, checkpointer, and hibernation on one substrate.
- Your agent runs model-written code as a core capability — the tool sandbox is now a top-tier requirement, so pick a host offering per-call hardware-virtualized isolation instead of bolting subprocess onto a web worker.
- Your 'graph' is really one model call and one tool lookup — use a serverless function and don't let anyone talk you into a platform.
Whatever you shortlist, prove it with a spike rather than a spreadsheet. Build the smallest graph that exercises your requirements — it streams, it parks on an interrupt, it gets deployed over while parked, it resumes on a different process, and it calls a tool that runs generated code — then run it on your top two. Every platform handles the happy path; you're shopping for the one that handles the interrupt, the deploy, and the rm -rf.
Frequently asked questions
Can I deploy a LangGraph agent on serverless functions?
You can, but usually only for short, stateless graphs. Functions have maximum execution durations, and a LangGraph run that spans many model calls — or parks on a human-in-the-loop interrupt for hours or days — does not fit inside them. Streaming from a function is supported on some platforms as a specific, constrained feature rather than a default, so verify it per platform, and the stateless invocation model means every super-step pays checkpointer round-trips against a database that functions are historically awkward at pooling connections to. Functions are excellent as glue around an agent — receiving an approval webhook, enqueuing a resume, running a single-tool lookup — and a poor fit as the agent runtime itself.
Do I need Postgres for a LangGraph checkpointer in production?
You need a durable, shared store, and Postgres is the common answer because LangGraph ships a first-party Postgres checkpointer and most teams already run one. The in-memory saver is a development convenience: it loses every thread on restart and isn't shared across replicas, so a load balancer routing the next request to a different instance sees no state at all. Whatever you choose, treat it as production data — automated backups you have tested a restore from, point-in-time recovery if runs are long-lived, and a plan for schema migrations when you upgrade the framework. The compute in front of the checkpointer is disposable; the checkpointer is not.
How do I handle human-in-the-loop pauses without paying for idle compute?
Separate the state from the process. If the checkpointer is durable, the worker that resumes a run does not have to be the one that started it, so compute can shut down entirely while a human deliberates and a different worker picks the thread up later by thread_id. That makes scale-to-zero hosting viable: Fly Machines can stop and start on demand, and PandaStack can hibernate the agent's microVM to a snapshot and restore it at roughly 179ms p50. The pattern to avoid is holding an open in-process pause on a warm container, which converts a human's response time directly into your compute bill.
Where should a LangGraph agent run the code its tools generate?
Not in the process running the graph. Model-generated code should execute in a disposable environment with its own kernel, its own filesystem, and no access to your database credentials or model API keys, created for the call and destroyed afterward. A shared-kernel container is a weak boundary for code an LLM wrote, especially once prompt injection is in scope, since anything the agent reads from the web or a user document is an instruction channel into your tool loop. Hardware-virtualized microVMs per tool call are the strong version of this; at minimum, isolate execution into a separate service with a distinct, minimal credential surface and a hard timeout.
Is LangGraph's managed platform worth it versus self-hosting?
It's worth it when your main risk is getting the runtime semantics wrong and your priority is shipping. Durable execution, checkpointing, streaming, and interrupt handling are designed together by the framework authors, which removes a category of subtle bugs you would otherwise find in production. Self-hosting wins when the deployment target is dictated by compliance or data residency, when the agent must live inside an existing network perimeter, or when your idle-cost profile demands scale-to-zero behavior the managed tiers don't offer. Either way the tool-execution sandbox remains your responsibility, because a managed graph runtime is not a managed place to run model-written code — so verify current tiers, limits, and self-hosted options against LangChain's own docs before deciding.
Keep reading
- Giving a LangChain agent a code-execution tool — The tool-side deep dive: wiring run_python safely, timeouts, and output truncation.
- Long-running sandboxes for AI agents — What changes when the environment outlives the request — TTLs, idle reaping, and hibernation.
- Resuming AI agent sessions — The other half of durable execution: picking a parked run back up on different compute.
- Best managed Postgres providers in 2026 — Choosing the database your checkpointer lives in, since that database is effectively the agent.
49ms p50 cold start. Fork, snapshot, and scale to zero.