A framework's runtime profile — how fast it boots, how much memory it holds, what artifact it deploys as, where it runs comfortably — shapes operational cost more than any benchmark suggests. For typical agent workloads the LLM dominates wall time and framework throughput rarely matters; what does matter is cold-start time on serverless or edge, memory cost per worker at scale, and whether your team can ship a single binary or has to ship an interpreter and a virtualenv. This chapter walks through each deployment axis and compares how the ten frameworks land on it.
A note on numbers in this chapter: cold-start times and memory footprints are ballparks, not benchmarks. Real numbers depend on which provider SDKs you import, how big your prompts and tools are, what observability stack you load, and which JVM / runtime version you're on. Use the ballparks for ordering, not absolute claims.
Cold start is how long your service takes from "process not running" to "first request answered." For long-running servers, you pay this cost once at boot and it doesn't matter much. For serverless functions and edge workers, you may pay it on every invocation that arrives during an idle window — and the user feels it directly.
Your agent runs on AWS Lambda. Most invocations land on a warm container and take 1.5 seconds (the LLM call). But once a minute, a request lands on a cold container and the framework has to import: the agent library, three provider SDKs, your observability stack, your tool implementations. With a typical Python agent stack, that import takes 2–4 seconds. With a Mastra agent on a Cloudflare Worker, ~50 ms (V8 isolates start in single-digit milliseconds; the bundle adds the rest). With a Genkit Go or Rig binary, sub-100 ms. The user who lands on a cold container experiences a request two to three times slower than the warm path.
Cold start hurts most under three conditions: (1) low or bursty traffic with idle intervals long enough to scale to zero, (2) edge deployment where workers are evicted aggressively, and (3) deployments with strict end-to-end SLAs where the cold-path outlier blows your p99. Long-running servers behind a load balancer don't really care.
| Framework | Cold-start ballpark | What dominates startup | AOT / native option? |
|---|---|---|---|
| LangChainPython | ~2–4 s | Python imports — LangChain core + provider SDKs + observability libs. | No. |
| LangGraphPython | ~2–4 s | Same as LangChain plus checkpointer / Pregel runtime. | No. |
| CrewAIPython | ~2–4 s | Python imports including LiteLLM and the memory stack. | No. |
| Google ADKPython | ~2–4 s | Python imports plus Google Cloud SDK if used. | No. |
| Semantic KernelPython | ~2–4 s | Python imports plus Azure SDK if Azure connectors used. | No. |
| MastraTypeScript | ~300–800 ms (Node) · ~50–100 ms (edge) | Node module loading on a server; on Cloudflare/Vercel edge the V8 isolate boots in single-digit ms and bundle eval dominates. | Yes — edge bundles run on V8 isolates with single-digit-ms boot. |
| MS Agent Framework.NET | ~200 ms (AOT) · ~1–2 s (JIT) | .NET host startup; AOT publish trims this dramatically. | Yes — .NET 8+ AOT; tiny footprint. |
| LangChain4jJava | ~1–2 s (Spring Boot JVM) · ~50 ms (Quarkus native) | JVM startup + Spring application context wiring; Quarkus + GraalVM native eliminates most of it. | Yes — Quarkus + GraalVM native image; CRaC for Spring Boot. |
| GenkitGo | ~30–80 ms | Go binary load + flow registration. | Native binary by default. |
| RigRust | ~20–60 ms | Rust binary load + Tokio runtime init. | Native binary by default. |
For a long-running server behind a load balancer, none of this matters — you eat cold start once. For serverless and edge, the ranking lines up: native binaries (Genkit Go, Rig), Quarkus + GraalVM native, and Mastra on edge runtimes all land under 100 ms; .NET AOT sits in the low hundreds; plain Spring Boot JVM is ~1–2 seconds; Python frameworks all sit in the 2–4 second range regardless of which one you pick.
If your deployment target is Cloudflare Workers, Vercel Edge, or AWS Lambda with strict cold-start SLAs, the language choice — not the framework choice within Python — dominates. If you're deploying to Cloud Run or Fargate behind a fronting service that keeps containers warm, framework cold start barely shows up.
A typical agent worker holds the framework's loaded code, the active session state, any caches, and any open connections to the model provider. How much memory each worker occupies determines how many you can run on a host, which translates directly to your compute bill at scale.
You provision a 4 GB memory instance for your agent backend. With a Python framework whose worker is 400 MB, you can fit roughly 8 workers on the box (leaving headroom for OS, cache, etc.). With a Go binary at 30 MB per process, you could fit 100+ — but you'd typically run one process and let goroutines handle concurrency. With a JVM on Spring Boot, one ~500 MB JVM is your worker, but it parallelises CPU work across cores within that one process.
Memory matters most under three conditions: (1) cloud bills where you pay per GB-hour of compute, (2) memory-limited edge or serverless functions, and (3) long-tail workloads where idle workers stack up. For a single team's prototype it's invisible; for a platform team running this at scale it's a real number.
| Framework | Per-worker ballpark | What's in memory | Multi-process model |
|---|---|---|---|
| LangChainPython | ~250–500 MB | Python interpreter + framework code + provider SDKs + active sessions. | Multiple worker processes (gunicorn / uvicorn workers); each carries its own copy. |
| LangGraphPython | ~250–500 MB | Same as LangChain; checkpoint state typically lives in external store. | Multiple worker processes. |
| CrewAIPython | ~300–600 MB | Python interpreter + LiteLLM + memory stack + active crew state in-memory. | Multiple worker processes; CrewAI's stateful in-memory model means session state grows the worker. |
| Google ADKPython | ~250–500 MB | Python interpreter + ADK + Google SDK if used. | Multiple worker processes. |
| Semantic KernelPython | ~200–450 MB | Python interpreter + SK + connectors used. | Multiple worker processes. |
| MastraTypeScript | ~150–300 MB (Node) · much smaller on edge runtimes | V8 + Node modules + active sessions; edge runtimes share V8 across isolates. | Single Node process handles concurrency via event loop; multiple processes for CPU parallelism. |
| MS Agent Framework.NET | ~80–150 MB (AOT) · ~250–400 MB (JIT) | .NET runtime + assemblies + DI container + sessions. | Single process parallelises CPU work across cores natively. |
| LangChain4jJava | ~300–600 MB (JVM) · ~80–150 MB (Quarkus native) | JVM + classloader + Spring/Quarkus context + active sessions. | Single JVM parallelises CPU work across cores; virtual threads on Java 21+ scale concurrency without extra memory per request. |
| GenkitGo | ~20–60 MB | Go binary + active sessions; very compact. | Single binary handles concurrency via goroutines. |
| RigRust | ~10–40 MB | Rust binary + Tokio runtime + active sessions. | Single binary handles concurrency via Tokio tasks. |
Rust and Go binaries are an order of magnitude smaller than the alternatives. .NET AOT and Quarkus native are competitive at 80–150 MB. Mastra on Node sits in the middle. Python frameworks all cluster around 250–500 MB, with CrewAI a touch heavier because of its in-memory stateful crew model. Plain JVM (Spring Boot without native compilation) is the heaviest at 300–600 MB, but it parallelises CPU within one process so you typically run fewer workers.
For most agent workloads the LLM call dwarfs the per-request memory cost, so the per-worker number multiplied by how many workers you need is the figure that matters. Python's fixed cost per worker is the operational tax it pays at scale; the others each have their own trade-offs (JVM startup time, .NET ecosystem assumptions, Node's single-threaded model, Rust's compile times) that show up elsewhere.
What artifact does each framework produce, and how do you ship it? A single statically linked binary is the simplest deploy story you can have; an interpreter plus a virtualenv plus a lock file is the most portable on developer machines but the most complex to ship reproducibly.
Your CI pipeline produces a deploy artifact. With a Go or Rust agent, that artifact
is one statically linked binary you copy into a scratch container — total image size
~30–80 MB. With a .NET AOT agent, similar story, ~50–120 MB. With a Spring Boot jar,
you ship a 50–80 MB jar and you need a JRE on the host (or you ship the JRE too,
making it ~250 MB). With a Node project, you ship the source plus
node_modules, typically 100–200 MB. With a Python project, you ship the
source plus a virtualenv plus a Python interpreter — typically 300–500 MB once you've
installed all the dependencies.
Bigger artifacts cost more storage in registries, more bandwidth on every deploy, and more time pulling images on each new node. They also tend to have more vulnerabilities to scan and patch. None of this kills you, but it adds operational drag.
| Framework | Deploy artifact | Container size ballpark | Single-file binary? |
|---|---|---|---|
| LangChainPython | Source + Python interpreter + virtualenv (or pip-installed packages). | ~300–500 MB | No — interpreter + dependencies are a tree of files. |
| LangGraphPython | Same as LangChain. | ~300–500 MB | No. |
| CrewAIPython | Same shape; LiteLLM and provider SDKs add weight. | ~350–600 MB | No. |
| Google ADKPython | Same shape; Cloud SDKs add weight if used. | ~300–500 MB | No. |
| Semantic KernelPython | Same shape; Azure SDKs add weight if used. | ~250–500 MB | No. |
| MastraTypeScript | Source + node_modules, or bundled JS for edge runtimes (Cloudflare / Vercel deployers). |
~100–250 MB (Node) · much smaller bundled for edge | No, but edge bundles are compact (single JS bundle). |
| MS Agent Framework.NET | Self-contained executable (AOT) or framework-dependent dll set (JIT). | ~50–120 MB (AOT) · ~150–250 MB (JIT) | Yes — .NET 8+ self-contained AOT publish produces a single executable. |
| LangChain4jJava | Spring Boot fat jar, Quarkus native binary, or app-server war. | ~100–250 MB (jar + JRE) · ~80–150 MB (Quarkus native) | Yes via Quarkus + GraalVM native image; jar requires a JRE. |
| GenkitGo | Single statically linked Go binary. | ~30–80 MB | Yes — native single binary. |
| RigRust | Single statically linked Rust binary. | ~30–80 MB | Yes — native single binary. |
The simplest deploy story belongs to Genkit Go and Rig — copy one binary into a scratch container, you're done. .NET AOT and Quarkus native are nearly as clean. Mastra's edge-bundled output is similarly compact for edge deployment, though Node-mode is heavier. Python and JVM-jar deployments require a runtime to be installed on the target machine. JVM jars are genuinely portable (same jar runs on any OS with a matching JRE); Python projects with native dependencies often need to be built per target OS. Both ship bigger artifacts than native binaries.
For containerised deployments to Kubernetes / ECS / Cloud Run, image size matters practically: more bandwidth on every deploy, more disk on every node, more time before a pod is ready. For developer-laptop workflows the artifact size barely matters — Python is the most ergonomic to install and iterate on.
Where can each framework realistically run? Long-running servers are the lowest common denominator — every framework runs there. The interesting comparison is at the edges: serverless functions with scale-to-zero behaviour, and edge runtimes (Cloudflare Workers, Vercel Edge, Deno Deploy) that impose strict bundle-size and API limits.
For a globally distributed chatbot, you'd ideally run the agent at the edge so users get sub-100 ms first-byte latency from the geographically nearest worker. Most frameworks can't run there — the runtime simply isn't supported by the edge platform, or the cold-start tax is too high to make it worthwhile. Serverless functions (Lambda, Cloud Functions, Azure Functions) sit in between — most frameworks can run there, but cold start affects the user experience. Long-running containers behind a load balancer absorb cold start once at boot and run fine for everything.
| Framework | Long-running server | Serverless (Lambda / Functions) | Edge runtime (Workers / Edge) |
|---|---|---|---|
| LangChainPython | Yes — FastAPI / Uvicorn / LangServe. | Yes, with cold-start tax. Stateless requests fit cleanly. | Not realistic — Python isn't supported by Workers/Edge. |
| LangGraphPython | Yes — usually behind LangSmith Deployment or your own FastAPI. | Yes, with cold-start tax. Use an external checkpointer. | Not realistic. |
| CrewAIPython | Yes — long-running server; CrewAI Cloud is the canonical hosted option. | Awkward — stateful in-memory crew model fights serverless stateless requests. | No. |
| Google ADKPython | Yes — Cloud Run primary target, also Vertex AI Agent Engine. | Yes — Cloud Run scales to zero; Lambda with cold-start tax. | No. |
| Semantic KernelPython | Yes — FastAPI or any Python web framework. | Yes, with cold-start tax. | No. |
| MastraTypeScript | Yes — Node, Next.js, any TS server. | Yes — bundled deployers for Vercel / AWS / Netlify. | Yes — bundled deployer for Cloudflare Workers; targets edge directly. |
| MS Agent Framework.NET | Yes — ASP.NET Core, Azure Container Apps. | Yes — Azure Functions; Lambda via .NET runtime. | Limited — .NET on edge is not yet mainstream; Azure Static Web Apps with Functions is closest. |
| LangChain4jJava | Yes — Spring Boot, Quarkus, Helidon, Micronaut. | Yes — best results with Quarkus native binaries (cold start ~50 ms). | No. |
| GenkitGo | Yes — Cloud Run primary target; any Go server. | Yes — Cloud Functions native; Lambda with custom runtime; Cloud Run scales to zero. | Limited — Go isn't on Cloudflare Workers; some edge platforms support WASM compilation. |
| RigRust | Yes — embed in Axum / actix-web; native binary. | Yes — Lambda via custom runtime; cold start sub-100 ms. | Possible via WASM compilation; requires custom build configuration. |
For long-running servers any of the ten frameworks works. For serverless, the ranking lines up with cold-start time — native-binary frameworks (Genkit Go, Rig, .NET AOT, Quarkus native) feel snappy on cold containers; Python feels noticeably slower; Mastra on Vercel sits in between. For edge runtimes, the picture collapses to one realistic option: Mastra. Cloudflare Workers and Vercel Edge run JavaScript / WASM, which rules out Python, JVM jars, and traditional Go / .NET deployments. For edge runtimes (Cloudflare Workers, Vercel Edge), Mastra is the only framework on this list that ships ready-to-deploy edge-compatible bundles.
Some frameworks ship a CLI runner you can use to start a dev server, a production server, or both. Others expect you to bring your own host framework (Spring Boot, ASP.NET Core, Express, etc.). For early development the bundled runners save real time; for production deployments the boundary between "framework runner" and "host framework" matters less.
On day one of a project, a built-in dev command lets you iterate on
agent code with file-watching reload, a playground UI for poking at the agent, and
basic observability — useful scaffolding that you'd otherwise hand-roll. By
production, most teams replace that runner with their company-standard hosting setup
(Spring Boot, ASP.NET Core, FastAPI with their auth and observability middleware),
so the production-runner column matters mostly for greenfield projects without that
opinionation.
| Framework | Dev runner | Production runner | Source |
|---|---|---|---|
| LangChainPython | Notebook / script — no first-party dev server. | LangServe — separate package, FastAPI-based HTTP server for Runnables. | langserve package |
| LangGraphPython | langgraph dev — local dev server with checkpointer + UI. |
langgraph up — containerise + deploy; LangSmith Deployment for hosted runtime. |
libs/cli/ · langgraph_api |
| CrewAIPython | CLI tools for crew scaffolding; no built-in HTTP dev server. | None built in — scripts or CrewAI Cloud (hosted, proprietary). | — |
| Google ADKPython | adk run (local) / adk web (FastAPI server with UI). |
adk deploy — Cloud Run helper; also Vertex AI Agent Engine. |
src/google/adk/cli/ |
| Semantic KernelPython | None built in — script or notebook. | None — integrate with FastAPI / ASP.NET Core hosting. | — |
| MastraTypeScript | mastra dev — file-watching dev server with playground UI. |
mastra start + bundled deployers for Vercel / Cloudflare / Netlify / AWS. |
packages/cli/ · packages/server/ · packages/deployer/ |
| MS Agent Framework.NET | None bundled — use dotnet run with ASP.NET Core minimal API. |
Microsoft.Agents.AI.Hosting packages — AddA2AServer(), MapA2AHttpJson() extensions for ASP.NET Core. |
Microsoft.Agents.AI.Hosting.* |
| LangChain4jJava | Quarkus dev mode (live reload) when used via quarkus-langchain4j; Spring Boot dev tools otherwise. |
None bundled — Spring Boot / Quarkus / Micronaut / Helidon are the host frameworks. | Quarkus + Spring Boot starters |
| GenkitGo | genkit start — dev server with prompt watching and Inspector UI. |
Built-in HTTP handler; deploy as a Go binary to Cloud Run / Cloud Functions. | go/genkit/servers.go |
| RigRust | None bundled — use cargo run with your chosen web framework. |
None bundled — wire your own HTTP layer (Axum / actix-web / tower). | — |
Four frameworks ship genuinely useful dev runners with hot reload and a built-in UI:
LangGraph (langgraph dev), ADK (adk web), Mastra
(mastra dev), and Genkit Go (genkit start). These cut day-one
scaffolding work meaningfully. For production, MS Agent Framework's
Microsoft.Agents.AI.Hosting extensions and Mastra's bundled deployers are
the most opinionated paths to a deployed agent — they wire ASP.NET Core or your edge
platform without you writing a host. Other frameworks expect you to choose a host
framework and integrate it yourself.
Source-grounded observations on deployment surfaces across the ten frameworks.
Genkit Go (~30–80 ms) and Rig (~20–60 ms) are the fastest. Quarkus + GraalVM native (~50 ms) and Mastra on edge runtimes (~50–100 ms) join them under 100 ms. .NET AOT sits around ~200 ms; plain Spring Boot JVM ~1–2 s; Python frameworks all sit at ~2–4 s.
Rig and Genkit Go workers are 10–60 MB. .NET AOT and Quarkus native ~80–150 MB. Mastra on Node ~150–300 MB. Python frameworks 250–500 MB. Plain JVM 300–600 MB but parallelises CPU within one process — fewer workers needed.
Genkit Go, Rig, .NET AOT, and Quarkus native produce one statically linked executable you copy into a scratch container. JVM jars need a JRE; Python and Node need their interpreters and dependencies. Single-binary deploys are simpler to ship reproducibly and faster to pull in CI.
Cloudflare Workers, Vercel Edge, and Deno Deploy run JavaScript / WASM. Of the ten frameworks, only Mastra ships ready-to-deploy edge-compatible bundles. Rig and Genkit Go are theoretically reachable via WASM compilation but require custom WASM packaging. Python and JVM frameworks aren't realistic for edge.
LangGraph (langgraph dev), ADK (adk web), Mastra
(mastra dev), and Genkit Go (genkit start) ship dev servers
with file-watching, an inspector UI, and useful scaffolding. The others expect
you to bring a host framework (Spring Boot, ASP.NET Core, FastAPI).
CrewAI's stateful in-memory crew model is the awkward fit on scale-to-zero serverless platforms — sessions evaporate when the worker recycles. LangGraph dodges this by externalising state via the checkpointer; ADK via SessionService; Mastra via pluggable storage. The others stay stateless by default and pass session data in/out per request.