showcase/shell-docs/src/content/docs/integrations/langgraph/quickstart.mdx
<OpsPlatformCTA variant="card" title="Ship LangGraph to production" body="Add persistent threads and the inspector with the Enterprise Intelligence Platform." ctaLabel="Create a free account" surface="docs_langgraph_quickstart" />
Before you begin, you'll need the following:
<SignupLink surface="docs_langgraph_quickstart_step1">Sign up for a free developer account</SignupLink> on our Enterprise Intelligence Platform to get a license key. You'll use it later to enable persistent threads and the inspector.
</Step>
<Step>
### Choose your starting point
You can either start fresh with our starter template or integrate CopilotKit into your existing LangGraph agent.
<TailoredContent
className="step"
id="agent"
>
<TailoredContentOption
id="starter"
title="Start from scratch"
description="Get started quickly with our ready-to-go starter application."
>
<Step>
### Run our CLI
```bash
npx copilotkit@latest create
```
The CLI walks you through:
- **Project name**
- **Enterprise Intelligence Platform** — persistent threads and the inspector. Choose **Yes** to scaffold a project pre-wired for the platform (the CLI walks you through sign-up, or you can [create an account](https://dashboard.operations.copilotkit.ai/?utm_source=docs&utm_medium=cta&utm_campaign=intelligence&utm_content=docs_cli_prompt) first), or **No** for a standard LangGraph setup.
- **Framework** — pick **LangGraph (Python)** or **LangGraph (JavaScript)**.
</Step>
<Step>
### Install dependencies
```npm
npm install
```
</Step>
<Step>
### Configure your environment
Create a `.env` file in your agent directory and add your OpenAI API key:
```plaintext title=".env"
OPENAI_API_KEY=your_openai_api_key
```
<Callout type="info" title="What about other models?">
The starter template is configured to use OpenAI's GPT-4o by default, but you can modify it to use any language model supported by LangGraph.
</Callout>
</Step>
<Step>
### Start the development server
<Tabs groupId="package-manager" items={['npm', 'pnpm', 'yarn', 'bun']}>
<Tab value="npm">
```bash
npm run dev
```
</Tab>
<Tab value="pnpm">
```bash
pnpm dev
```
</Tab>
<Tab value="yarn">
```bash
yarn dev
```
</Tab>
<Tab value="bun">
```bash
bun dev
```
</Tab>
</Tabs>
This will start both the UI and agent servers concurrently.
</Step>
</TailoredContentOption>
<TailoredContentOption
id="bring-your-own"
title="Use an existing agent"
description="I already have a LangGraph agent and want to add CopilotKit."
>
<Step>
### Initialize your agent project
If you don't already have a Python project set up, create one using `uv`:
```bash
uv init my-agent
cd my-agent
```
</Step>
<Step>
### Install LangGraph
Add the packages the agent code below imports:
```bash
uv add langgraph langchain-openai langchain-core python-dotenv
```
Both tabs below import all four. The **FastAPI** tab installs what
its own code needs on top of these — `ag-ui-langgraph`, `fastapi`,
`uvicorn` and `copilotkit` — in its own step; the LangSmith path
imports none of them, so they are not in this line.
<Callout type="warn" title="Project with pinned dependencies?">
`uv add` resolves and rewrites your lockfile. If your project
pins exact versions (`==`), add these to your dependency file by
hand instead so the rest of your pins stay put.
</Callout>
</Step>
<Step>
### Expose your agent via AG-UI
If you already have a LangGraph agent written, just reference the following code. In this step
we create a simple LangGraph agent for the sake of demonstration.
<Tabs groupId="deployment_method" items={['LangSmith', 'FastAPI']}>
<Tab value="LangSmith">
First, we'll create a simple LangGraph agent:
```python title="main.py"
from dotenv import load_dotenv
from langchain_core.messages import SystemMessage
from langchain_openai import ChatOpenAI
from langgraph.graph import END, START, MessagesState, StateGraph
load_dotenv()
async def mock_llm(state: MessagesState):
model = ChatOpenAI(model="gpt-4.1-mini")
system_message = SystemMessage(content="You are a helpful assistant.")
response = await model.ainvoke(
[
system_message,
*state["messages"],
]
)
return {"messages": response}
graph = StateGraph(MessagesState)
graph.add_node(mock_llm)
graph.add_edge(START, "mock_llm")
graph.add_edge("mock_llm", END)
graph = graph.compile()
```
<Callout type="warn" title="Do not add a checkpointer on this path">
`compile()` is called with no `checkpointer=` on purpose. The
LangGraph API server owns persistence and injects its own
checkpointer at run time. If you compile a custom one in,
`langgraph dev` refuses to load the graph
(`ValueError: ... includes a custom checkpointer ... persistence is
handled automatically by the platform`) and a deployed graph
ignores it. The **FastAPI** tab is the opposite case — see the
note there.
</Callout>
Then to test and deploy with LangSmith, we'll also need a `langgraph.json`
```sh
touch langgraph.json
```
```json title="langgraph.json"
{
"python_version": "3.12",
"dockerfile_lines": [],
"dependencies": ["."],
"package_manager": "uv",
"graphs": {
"sample_agent": "./main.py:graph"
},
"env": ".env"
}
```
</Tab>
<Tab value="FastAPI">
First, add the `ag-ui-langgraph` package to your project:
```bash
uv add ag-ui-langgraph fastapi uvicorn copilotkit
```
Then create a simple LangGraph agent, add a FastAPI app, and build attach our agent as an AG-UI endpoint.
```python title="main.py" doctest="server"
import os
# [!code highlight:2]
from dotenv import load_dotenv
from ag_ui_langgraph import add_langgraph_fastapi_endpoint
from copilotkit import LangGraphAGUIAgent
from fastapi import FastAPI
from langgraph.graph import END, START, MessagesState, StateGraph
from langchain_core.messages import SystemMessage
from langchain_openai import ChatOpenAI
from langgraph.checkpoint.memory import MemorySaver
import uvicorn
load_dotenv()
async def mock_llm(state: MessagesState):
model = ChatOpenAI(model="gpt-4.1-mini")
system_message = SystemMessage(content="You are a helpful assistant.")
response = await model.ainvoke(
[
system_message,
*state["messages"],
]
)
return {"messages": response}
graph = StateGraph(MessagesState)
graph.add_node(mock_llm)
graph.add_edge(START, "mock_llm")
graph.add_edge("mock_llm", END)
graph = graph.compile(
checkpointer=MemorySaver()
)
app = FastAPI()
# [!code highlight:9]
add_langgraph_fastapi_endpoint(
app=app,
agent=LangGraphAGUIAgent(
name="sample_agent",
description="An example agent to use as a starting point for your own agent.",
graph=graph,
),
path="/",
)
def main():
"""Run the uvicorn server."""
uvicorn.run(
"main:app",
host="0.0.0.0",
port=8123,
reload=True,
)
if __name__ == "__main__":
main()
```
<Callout type="info" title="Why this tab compiles with a checkpointer">
Here you run the graph yourself, so nothing supplies
persistence. `ag-ui-langgraph` reads thread state via
`graph.aget_state(...)`, which raises
`ValueError: No checkpointer set` on a graph compiled without
one — hence `MemorySaver()`. It keeps state in process memory
only; swap in a durable saver (e.g. Postgres) for production.
Do **not** copy this into the LangSmith tab's graph.
</Callout>
`main.py` sets uvicorn's port to `8123` above, which is the
port the runtime route below expects. Change both together if
you pick a different one.
</Tab>
</Tabs>
<Callout type="info" title="What is AG-UI?">
AG-UI is an open protocol for frontend-agent communication.
</Callout>
</Step>
<Step>
### Configure your environment
Create a `.env` file in your agent directory and add your OpenAI API key:
```plaintext title=".env"
OPENAI_API_KEY=your_openai_api_key
```
<Callout type="info" title="What about other models?">
The starter template is configured to use OpenAI's GPT-4o by default, but you can modify it to use any language model supported by LangGraph.
</Callout>
</Step>
<Step>
### Create your frontend
CopilotKit works with any React-based frontend. We'll use Next.js for this example.
```bash
npx create-next-app@latest frontend
cd frontend
```
</Step>
<Step>
### Install CopilotKit packages
```npm
npm install @copilotkit/react-core @copilotkit/runtime
```
The components used below (`CopilotKit`, `CopilotSidebar`) and the
stylesheet all come from `@copilotkit/react-core/v2`, so
`@copilotkit/react-ui` is not needed for this setup.
</Step>
<Step>
### Setup Copilot Runtime
Create an API route to connect CopilotKit to your LangGraph agent:
```sh
mkdir -p app/api/copilotkit && touch app/api/copilotkit/route.ts
```
<Callout type="warn" title="This route is enough for chat, not for Threads or the Inspector">
A single `POST /api/copilotkit` is the *minimum* wiring: it runs
the runtime in single-route mode, which is all chat needs.
Persistent Threads and the Inspector's saved-Threads list need the
multi-route handler instead — a catch-all
`app/api/copilotkit/[[...slug]]/route.ts` that exports `GET`,
`POST`, `PATCH` and `DELETE`, so list, rename, archive and delete
requests can reach the runtime. If the Inspector shows **Finish
setting up Rich Threads**, this is why. See
[Runtime HTTP endpoints](/backend/runtime-endpoints#enable-rich-threads-routes)
for the route and the provider setup that goes with it.
</Callout>
<Tabs groupId="deployment_method" items={['LangSmith', 'FastAPI']}>
<Tab value="LangSmith">
```tsx title="app/api/copilotkit/route.ts"
import {
CopilotRuntime,
ExperimentalEmptyAdapter,
copilotRuntimeNextJSAppRouterEndpoint,
} from "@copilotkit/runtime";
// [!code highlight]
import { LangGraphAgent } from "@copilotkit/runtime/langgraph";
import { NextRequest } from "next/server";
const serviceAdapter = new ExperimentalEmptyAdapter();
const runtime = new CopilotRuntime({
agents: {
// [!code highlight:5]
sample_agent: new LangGraphAgent({
deploymentUrl: process.env.LANGGRAPH_DEPLOYMENT_URL || "http://localhost:8123",
graphId: "sample_agent",
langsmithApiKey: process.env.LANGSMITH_API_KEY || "",
}),
}
});
export const POST = async (req: NextRequest) => {
const { handleRequest } = copilotRuntimeNextJSAppRouterEndpoint({
runtime,
serviceAdapter,
endpoint: "/api/copilotkit",
});
return handleRequest(req);
};
```
</Tab>
<Tab value="FastAPI">
```tsx title="app/api/copilotkit/route.ts"
import {
CopilotRuntime,
ExperimentalEmptyAdapter,
copilotRuntimeNextJSAppRouterEndpoint,
} from "@copilotkit/runtime";
// [!code highlight]
import { LangGraphHttpAgent } from "@copilotkit/runtime/langgraph";
import { NextRequest } from "next/server";
const serviceAdapter = new ExperimentalEmptyAdapter();
const runtime = new CopilotRuntime({
agents: {
// [!code highlight:3]
sample_agent: new LangGraphHttpAgent({
url: process.env.LANGGRAPH_DEPLOYMENT_URL || "http://localhost:8123",
}),
}
});
export const POST = async (req: NextRequest) => {
const { handleRequest } = copilotRuntimeNextJSAppRouterEndpoint({
runtime,
serviceAdapter,
endpoint: "/api/copilotkit",
});
return handleRequest(req);
};
```
</Tab>
</Tabs>
</Step>
<Step>
### Configure CopilotKit Provider
Wrap your application with the CopilotKit provider:
<Callout type="info" title="Which provider goes with which handler?">
`<CopilotKit>` here is the backward-compatible wrapper: it defaults
`useSingleEndpoint` to `true`, which is the matching half of the
single-route `copilotRuntimeNextJSAppRouterEndpoint` above. `<CopilotKitProvider>`
is the v2 provider from the same package and detects the transport from
`/info` instead. They are not aliases — see
[Provider and handler pairs](/backend/runtime-endpoints#provider-and-handler-pairs).
</Callout>
```tsx title="app/layout.tsx"
// [!code highlight:2]
import { CopilotKit } from "@copilotkit/react-core/v2";
import "@copilotkit/react-core/v2/styles.css";
import './globals.css';
// ...
export default function RootLayout({ children }: {children: React.ReactNode}) {
return (
<html lang="en">
<body>
<CopilotKit runtimeUrl="/api/copilotkit" agent="sample_agent">
{children}
</CopilotKit>
</body>
</html>
);
}
```
</Step>
<Step>
### Add the chat interface
Add the CopilotSidebar component to your page:
```tsx title="app/page.tsx"
import { CopilotSidebar } from "@copilotkit/react-core/v2"; // [!code highlight:1]
export default function Page() {
return (
<main>
<h1>Your App</h1>
<CopilotSidebar />
</main>
);
}
```
</Step>
<Step>
### Start your agent
From your agent directory, start the agent server:
<Tabs groupId="deployment_method" items={['LangSmith', 'FastAPI']}>
<Tab value="LangSmith">
```bash
cd ..
npx @langchain/langgraph-cli dev --port 8123 --no-browser
```
<Callout type="warn" title="Port 8123 is not the default">
A bare `langgraph dev` (either the Python `langgraph-cli` or
`@langchain/langgraph-cli`) serves on **2024**. This guide
pins **8123** with `--port 8123` to match the
`http://localhost:8123` fallback in the route above. Keep the
flag, or drop it and change the route's URL to
`http://localhost:2024` — but do not mix the two, or the
runtime will fail to connect with no diagnostic beyond a
connection error.
</Callout>
</Tab>
<Tab value="FastAPI">
```bash
cd ..
uv run main.py
```
This serves on **8123**, the port set in `main.py`'s
`uvicorn.run(...)` call.
</Tab>
</Tabs>
Your agent will be available at `http://localhost:8123` for both
tabs above.
</Step>
<Step>
### Start your UI
In a separate terminal, navigate to your frontend directory and start the development server:
<Tabs groupId="package-manager" items={['npm', 'pnpm', 'yarn', 'bun']}>
<Tab value="npm">
```bash
cd frontend
npm run dev
```
</Tab>
<Tab value="pnpm">
```bash
cd frontend
pnpm dev
```
</Tab>
<Tab value="yarn">
```bash
cd frontend
yarn dev
```
</Tab>
<Tab value="bun">
```bash
cd frontend
bun dev
```
</Tab>
</Tabs>
</Step>
</TailoredContentOption>
</TailoredContent>
</Step>
<Step>
### 🎉 Start chatting!
Your AI agent is now ready to use! Try asking it some questions:
```
Can you tell me a joke?
```
```
Can you help me understand AI?
```
```
What do you think about React?
```
<Accordions className="mb-4">
<Accordion title="Troubleshooting">
- **Connection issues? Keep `localhost`, don't swap in a literal IP.** Which loopback address reaches the agent depends on the runtime, and `0.0.0.0` is a bind-all address for a server, never a valid target in a client URL.
<Tabs groupId="language_langgraph_agent" items={['Python', 'TypeScript']} default="Python" persist>
<Tab value="Python">
`langgraph dev` (the Python CLI) defaults to `--host 127.0.0.1`, so both `http://127.0.0.1:8123` and `http://localhost:8123` reach it. `http://[::1]:8123` does not — the server is not listening on IPv6.
</Tab>
<Tab value="TypeScript">
`@langchain/langgraph-cli` (the `langgraphjs` binary) defaults to `--host localhost`, which Node resolves to IPv6 on a dual-stack machine, binding `::1` **only**. So `http://localhost:8123` and `http://[::1]:8123` reach it, while `http://127.0.0.1:8123` is refused by that same running server — switching to `127.0.0.1` is what breaks it. If you need IPv4, bind it explicitly with `langgraphjs dev --host 127.0.0.1`.
</Tab>
</Tabs>
- Make sure your agent folder contains a `langgraph.json` file
- In the `langgraph.json` file, reference the path to a `.env` file
- Check that your OpenAI API key is correctly set in the `.env` file
- If using an existing agent, ensure your LangSmith API key is also configured
- Make sure you're in the same folder as your `langgraph.json` file when running the `langgraph dev` command
- **Connection refused from the runtime?** Check the port. A bare `langgraph dev` listens on `2024`; this guide's start command pins `8123` with `--port 8123`. The runtime's `LANGGRAPH_DEPLOYMENT_URL` (or its fallback) has to name the port the agent actually bound.
- **"graph is nullish" error (JavaScript starters):** This means the LangGraph CLI couldn't load your graph. Ensure the export name in your `langgraph.json` matches your code (e.g., `"starterAgent": "./src/agent.ts:graph"` requires `export const graph = ...` in `agent.ts`). Also verify all dependencies are installed with `npm install` in your agent directory.
- Make sure the runtime endpoint path matches the `runtimeUrl` in your CopilotKit provider
</Accordion>
</Accordions>
</Step>
If you're planning to deploy your LangGraph agent to AWS Bedrock AgentCore, see the AgentCore deploy guide.
Now that you have your basic agent setup, explore these advanced features:
<Cards> <Card title="Implement Human in the Loop" description="Allow your users and agents to collaborate together on tasks." href="/langgraph/human-in-the-loop" icon={<UserIcon />} /> <Card title="Utilize Shared State" description="Learn how to synchronize your agent's state with your UI's state, and vice versa." href="/langgraph/shared-state" icon={<RepeatIcon />} /> <Card title="Add some generative UI" description="Render your agent's progress and output in the UI." href="/langgraph/generative-ui/tool-rendering" icon={<PaintbrushIcon />} /> <Card title="Setup frontend actions" description="Give your agent the ability to call frontend tools, directly updating your application." href="/langgraph/frontend-tools" icon={<WrenchIcon />} /> </Cards><video src="https://cdn.copilotkit.ai/docs/copilotkit/images/coagents/chat-example.mp4" className="rounded-lg shadow-xl" loop playsInline controls autoPlay muted />