diff --git a/src/langgraph-platform/use-remote-graph.mdx b/src/langgraph-platform/use-remote-graph.mdx
index 7e801c788..7554fd301 100644
--- a/src/langgraph-platform/use-remote-graph.mdx
+++ b/src/langgraph-platform/use-remote-graph.mdx
@@ -1,109 +1,116 @@
---
-title: How to interact with the deployment using RemoteGraph
-sidebarTitle: Interact with the deployment using RemoteGraph
+title: How to interact with a deployment using RemoteGraph
+sidebarTitle: Interact with a deployment using RemoteGraph
---
-
-**Prerequisites**
-* [LangGraph Platform](/langgraph-platform/index)
-* [LangGraph Server](/langgraph-platform/langgraph-server)
-
-`RemoteGraph` is an interface that allows you to interact with your LangGraph Platform deployment as if it were a regular, locally-defined LangGraph graph (e.g. a `CompiledGraph`). This guide shows you how you can initialize a `RemoteGraph` and interact with it.
+[`RemoteGraph`](https://langchain-ai.github.io/langgraph/reference/remote_graph) is a client-side interface that allows you to interact with your [deployment](/langgraph-platform/deployment-options) as if it were a local graph. It provides API parity with [`CompiledGraph`](/oss/langgraph/graph-api#compiling-your-graph), which means that you can use the same methods (`invoke()`, `stream()`, `get_state()`, etc.) in your development and production environments. This page describes how to initialize a `RemoteGraph` and interact with it.
-## Initializing the graph
+`RemoteGraph` is useful for the following:
+
+- Separation of development and deployment: Build and test a graph locally with `CompiledGraph`, deploy it to LangGraph Platform, and then [use `RemoteGraph`](#initialize-the-graph) to call it in production while working with the same API interface.
+- Thread-level persistence: [Persist and fetch the state](#persist-state-at-the-thread-level) of a conversation across calls with a thread ID.
+- Subgraph embedding: Compose modular graphs for a multi-agent workflow by embedding a `RemoteGraph` as a [subgraph](#use-as-a-subgraph) within another graph.
+- Reusable workflows: Use deployed graphs as nodes or [tools](https://langchain-ai.github.io/langgraph/reference/remote_graph/#langgraph.pregel.remote.RemoteGraph.as_tool), so that you can reuse and expose complex logic.
+
+## Prerequisites
+
+Before getting started with `RemoteGraph`, make sure you have:
+
+- Access to [LangGraph Platform](/langgraph-platform/index), where your graphs are developed and managed.
+- A running [LangGraph Server](/langgraph-platform/langgraph-server), which hosts your deployed graphs for remote interaction.
+
+## Initialize the graph
When initializing a `RemoteGraph`, you must always specify:
-* `name`: the name of the graph you want to interact with **or** an assistant ID. If you specify a graph name, the default assistant will be used. If you specify an assistant ID, that specific assistant will be used. The graph name is the same name you use in `langgraph.json` configuration file for your deployment.
-* `api_key`: a valid LangSmith API key. Can be set as an environment variable (`LANGSMITH_API_KEY`) or passed directly via the `api_key` argument. The API key could also be provided via the `client` / `sync_client` arguments, if `LangGraphClient` / `SyncLangGraphClient` were initialized with `api_key` argument.
+- `name`: The name of the graph you want to interact with **or** an assistant ID. If you specify a graph name, the default assistant will be used. If you specify an assistant ID, that specific assistant will be used. The graph name is the same name you use in the `langgraph.json` configuration file for your deployment.
+- `api_key`: A valid [LangSmith API key](/langsmith/create-account-api-key). You can set as an environment variable (`LANGSMITH_API_KEY`) or pass directly in the `api_key` argument. You can also provide the API key in the `client` / `sync_client` arguments, if `LangGraphClient` / `SyncLangGraphClient` was initialized with the `api_key` argument.
Additionally, you have to provide one of the following:
-* `url`: URL of the deployment you want to interact with. If you pass `url` argument, both sync and async clients will be created using the provided URL, headers (if provided) and default configuration values (e.g. timeout, etc).
-* `client`: a `LangGraphClient` instance for interacting with the deployment asynchronously (e.g. using `.astream()`, `.ainvoke()`, `.aget_state()`, `.aupdate_state()`, etc.)
-* `sync_client`: a `SyncLangGraphClient` instance for interacting with the deployment synchronously (e.g. using `.stream()`, `.invoke()`, `.get_state()`, `.update_state()`, etc.)
+- [`url`](#use-a-url): The URL of the deployment you want to interact with. If you pass the `url` argument, both sync and async clients will be created using the provided URL, headers (if provided), and default configuration values (e.g., timeout).
+- [`client`](#use-a-client): A `LangGraphClient` instance for interacting with the deployment asynchronously (e.g., using `.astream()`, `.ainvoke()`, `.aget_state()`, `.aupdate_state()`).
+- `sync_client`: A `SyncLangGraphClient` instance for interacting with the deployment synchronously (e.g., using `.stream()`, `.invoke()`, `.get_state()`, `.update_state()`).
-If you pass both `client` or `sync_client` as well as `url` argument, they will take precedence over the `url` argument. If none of the `client` / `sync_client` / `url` arguments are provided, `RemoteGraph` will raise a `ValueError` at runtime.
+If you pass both `client` or `sync_client` as well as the `url` argument, they will take precedence over the `url` argument. If none of the `client` / `sync_client` / `url` arguments are provided, `RemoteGraph` will raise a `ValueError` at runtime.
-### Using URL
+### Use a URL
+
+
+
+```python Python
+from langgraph.pregel.remote import RemoteGraph
+
+url = ""
+
+# Using graph name (uses default assistant)
+graph_name = "agent"
+remote_graph = RemoteGraph(graph_name, url=url)
-
-
- ```python
- from langgraph.pregel.remote import RemoteGraph
+# Using assistant ID
+assistant_id = ""
+remote_graph = RemoteGraph(assistant_id, url=url)
+```
- url =
+```typescript JavaScript
+import { RemoteGraph } from "@langchain/langgraph/remote";
- # Using graph name (uses default assistant)
- graph_name = "agent"
- remote-graph = RemoteGraph(graph_name, url=url)
+const url = "";
- # Using assistant ID
- assistant_id =
- remote-graph = RemoteGraph(assistant_id, url=url)
- ```
-
-
- ```ts
- import { RemoteGraph } from "@langchain/langgraph/remote";
+// Using graph name (uses default assistant)
+const graphName = "agent";
+const remoteGraph = new RemoteGraph({ graphId: graphName, url });
- const url = ``;
+// Using assistant ID
+const assistantId = "";
+const remoteGraph = new RemoteGraph({ graphId: assistantId, url });
+```
- // Using graph name (uses default assistant)
- const graphName = "agent";
- const remoteGraph = new RemoteGraph({ graphId: graphName, url });
+
- // Using assistant ID
- const assistantId = ``;
- const remoteGraph = new RemoteGraph({ graphId: assistantId, url });
- ```
-
-
+### Use a client
-### Using clients
+
-
-
- ```python
- from langgraph_sdk import get_client, get_sync_client
- from langgraph.pregel.remote import RemoteGraph
+```python Python
+from langgraph_sdk import get_client, get_sync_client
+from langgraph.pregel.remote import RemoteGraph
- url =
- client = get_client(url=url)
- sync_client = get_sync_client(url=url)
+url = ""
+client = get_client(url=url)
+sync_client = get_sync_client(url=url)
- # Using graph name (uses default assistant)
- graph_name = "agent"
- remote-graph = RemoteGraph(graph_name, client=client, sync_client=sync_client)
+# Using graph name (uses default assistant)
+graph_name = "agent"
+remote_graph = RemoteGraph(graph_name, client=client, sync_client=sync_client)
- # Using assistant ID
- assistant_id =
- remote-graph = RemoteGraph(assistant_id, client=client, sync_client=sync_client)
- ```
-
-
- ```ts
- import { Client } from "@langchain/langgraph-sdk";
- import { RemoteGraph } from "@langchain/langgraph/remote";
+# Using assistant ID
+assistant_id = ""
+remote_graph = RemoteGraph(assistant_id, client=client, sync_client=sync_client)
+```
- const client = new Client({ apiUrl: `` });
+```typescript JavaScript
+import { Client } from "@langchain/langgraph-sdk";
+import { RemoteGraph } from "@langchain/langgraph/remote";
- // Using graph name (uses default assistant)
- const graphName = "agent";
- const remoteGraph = new RemoteGraph({ graphId: graphName, client });
+const client = new Client({ apiUrl: "" });
- // Using assistant ID
- const assistantId = ``;
- const remoteGraph = new RemoteGraph({ graphId: assistantId, client });
- ```
-
-
+// Using graph name (uses default assistant)
+const graphName = "agent";
+const remoteGraph = new RemoteGraph({ graphId: graphName, client });
-## Invoking the graph
+// Using assistant ID
+const assistantId = "";
+const remoteGraph = new RemoteGraph({ graphId: assistantId, client });
+```
-Since `RemoteGraph` is a `Runnable` that implements the same methods as `CompiledGraph`, you can interact with it the same way you normally would with a compiled graph, i.e. by calling `.invoke()`, `.stream()`, `.get_state()`, `.update_state()`, etc (as well as their async counterparts).
+
+
+## Invoke the graph
+
+`RemoteGraph` implements the same Runnable interface as `CompiledGraph`, so you can use it in the same way as a compiled graph. It supports the full set of standard methods, including `.invoke()`, `.stream()`, `.get_state()`, and `.update_state()`, as well as their asynchronous variants.
### Asynchronously
@@ -111,36 +118,35 @@ Since `RemoteGraph` is a `Runnable` that implements the same methods as `Compile
To use the graph asynchronously, you must provide either the `url` or `client` when initializing the `RemoteGraph`.
-
-
- ```python
- # invoke the graph
- result = await remote-graph.ainvoke({
- "messages": [{"role": "user", "content": "what's the weather in sf"}]
- })
-
- # stream outputs from the graph
- async for chunk in remote-graph.astream({
- "messages": [{"role": "user", "content": "what's the weather in la"}]
- }):
- print(chunk)
- ```
-
-
- ```ts
- // invoke the graph
- const result = await remoteGraph.invoke({
- messages: [{role: "user", content: "what's the weather in sf"}]
- })
-
- // stream outputs from the graph
- for await (const chunk of await remoteGraph.stream({
- messages: [{role: "user", content: "what's the weather in la"}]
- })):
- console.log(chunk)
- ```
-
-
+
+
+```python Python
+# invoke the graph
+result = await remote_graph.ainvoke({
+ "messages": [{"role": "user", "content": "what's the weather in sf"}]
+})
+
+# stream outputs from the graph
+async for chunk in remote_graph.astream({
+ "messages": [{"role": "user", "content": "what's the weather in la"}]
+}):
+ print(chunk)
+```
+
+```typescript JavaScript
+// invoke the graph
+const result = await remoteGraph.invoke({
+ messages: [{role: "user", content: "what's the weather in sf"}]
+})
+
+// stream outputs from the graph
+for await (const chunk of await remoteGraph.stream({
+ messages: [{role: "user", content: "what's the weather in la"}]
+})):
+ console.log(chunk)
+```
+
+
### Synchronously
@@ -148,142 +154,145 @@ To use the graph asynchronously, you must provide either the `url` or `client` w
To use the graph synchronously, you must provide either the `url` or `sync_client` when initializing the `RemoteGraph`.
-
-
- ```python
- # invoke the graph
- result = remote-graph.invoke({
- "messages": [{"role": "user", "content": "what's the weather in sf"}]
- })
-
- # stream outputs from the graph
- for chunk in remote-graph.stream({
- "messages": [{"role": "user", "content": "what's the weather in la"}]
- }):
- print(chunk)
- ```
-
-
-
-## Thread-level persistence
-
-By default, the graph runs (i.e. `.invoke()` or `.stream()` invocations) are stateless - the checkpoints and the final state of the graph are not persisted. If you would like to persist the outputs of the graph run (for example, to enable human-in-the-loop features), you can create a thread and provide the thread ID via the `config` argument, same as you would with a regular compiled graph:
-
-
-
- ```python
- from langgraph_sdk import get_sync_client
- url =
- graph_name = "agent"
- sync_client = get_sync_client(url=url)
- remote-graph = RemoteGraph(graph_name, url=url)
-
- # create a thread (or use an existing thread instead)
- thread = sync_client.threads.create()
-
- # invoke the graph with the thread config
- config = {"configurable": {"thread_id": thread["thread_id"]}}
- result = remote-graph.invoke({
- "messages": [{"role": "user", "content": "what's the weather in sf"}]
- }, config=config)
-
- # verify that the state was persisted to the thread
- thread_state = remote-graph.get_state(config)
- print(thread_state)
- ```
-
-
- ```ts
- import { Client } from "@langchain/langgraph-sdk";
- import { RemoteGraph } from "@langchain/langgraph/remote";
-
- const url = ``;
- const graphName = "agent";
- const client = new Client({ apiUrl: url });
- const remoteGraph = new RemoteGraph({ graphId: graphName, url });
-
- // create a thread (or use an existing thread instead)
- const thread = await client.threads.create();
-
- // invoke the graph with the thread config
- const config = { configurable: { thread_id: thread.thread_id }};
- const result = await remoteGraph.invoke({
- messages: [{ role: "user", content: "what's the weather in sf" }],
- }, config);
-
- // verify that the state was persisted to the thread
- const threadState = await remoteGraph.getState(config);
- console.log(threadState);
- ```
-
-
-
-## Using as a subgraph
+
+
+```python Python
+# invoke the graph
+result = remote_graph.invoke({
+ "messages": [{"role": "user", "content": "what's the weather in sf"}]
+})
+
+# stream outputs from the graph
+for chunk in remote_graph.stream({
+ "messages": [{"role": "user", "content": "what's the weather in la"}]
+}):
+ print(chunk)
+```
+
+
+
+## Persist state at the thread level
+
+By default, graph runs (for example, calls made with `.invoke()` or `.stream()`) are stateless, which means that intermediate checkpoints and the final state are not persisted after a run.
+
+If you want to preserve the outputs of a run—for example, to support human-in-the-loop workflows—you can create a thread and pass its ID through the `config` argument. This works the same way as with a regular compiled graph:
+
+
+
+```python Python
+from langgraph_sdk import get_sync_client
+
+url = ""
+graph_name = "agent"
+sync_client = get_sync_client(url=url)
+remote_graph = RemoteGraph(graph_name, url=url)
+
+# create a thread (or use an existing thread instead)
+thread = sync_client.threads.create()
+
+# invoke the graph with the thread config
+config = {"configurable": {"thread_id": thread["thread_id"]}}
+result = remote_graph.invoke({
+ "messages": [{"role": "user", "content": "what's the weather in sf"}]
+}, config=config)
+
+# verify that the state was persisted to the thread
+thread_state = remote_graph.get_state(config)
+print(thread_state)
+```
+
+```typescript JavaScript
+import { Client } from "@langchain/langgraph-sdk";
+import { RemoteGraph } from "@langchain/langgraph/remote";
+
+const url = "";
+const graphName = "agent";
+const client = new Client({ apiUrl: url });
+const remoteGraph = new RemoteGraph({ graphId: graphName, url });
+
+// create a thread (or use an existing thread instead)
+const thread = await client.threads.create();
+
+// invoke the graph with the thread config
+const config = { configurable: { thread_id: thread.thread_id }};
+const result = await remoteGraph.invoke({
+ messages: [{ role: "user", content: "what's the weather in sf" }],
+}, config);
+
+// verify that the state was persisted to the thread
+const threadState = await remoteGraph.getState(config);
+console.log(threadState);
+```
+
+
+
+## Use as a subgraph
If you need to use a `checkpointer` with a graph that has a `RemoteGraph` subgraph node, make sure to use UUIDs as thread IDs.
-Since the `RemoteGraph` behaves the same way as a regular `CompiledGraph`, it can be also used as a subgraph in another graph. For example:
-
-
-
- ```python
- from langgraph_sdk import get_sync_client
- from langgraph.graph import StateGraph, MessagesState, START
- from typing import TypedDict
-
- url =
- graph_name = "agent"
- remote-graph = RemoteGraph(graph_name, url=url)
-
- # define parent graph
- builder = StateGraph(MessagesState)
- # add remote graph directly as a node
- builder.add_node("child", remote-graph)
- builder.add_edge(START, "child")
- graph = builder.compile()
-
- # invoke the parent graph
- result = graph.invoke({
- "messages": [{"role": "user", "content": "what's the weather in sf"}]
- })
- print(result)
-
- # stream outputs from both the parent graph and subgraph
- for chunk in graph.stream({
- "messages": [{"role": "user", "content": "what's the weather in sf"}]
- }, subgraphs=True):
- print(chunk)
- ```
-
-
- ```ts
- import { MessagesAnnotation, StateGraph, START } from "@langchain/langgraph";
- import { RemoteGraph } from "@langchain/langgraph/remote";
-
- const url = ``;
- const graphName = "agent";
- const remoteGraph = new RemoteGraph({ graphId: graphName, url });
-
- // define parent graph and add remote graph directly as a node
- const graph = new StateGraph(MessagesAnnotation)
- .addNode("child", remoteGraph)
- .addEdge(START, "child")
- .compile()
-
- // invoke the parent graph
- const result = await graph.invoke({
- messages: [{ role: "user", content: "what's the weather in sf" }]
- });
- console.log(result);
-
- // stream outputs from both the parent graph and subgraph
- for await (const chunk of await graph.stream({
- messages: [{ role: "user", content: "what's the weather in la" }]
- }, { subgraphs: true })) {
- console.log(chunk);
- }
- ```
-
-
+A graph can also call out to multiple `RemoteGraph` instances as [_subgraph_](/oss/langgraph/subgraphs) nodes. This allows for modular, scalable workflows where different responsibilities are split across separate graphs.
+
+`RemoteGraph` exposes the same interface as a regular `CompiledGraph`, so you can use it directly as a subgraph inside another graph. For example:
+
+
+
+```python Python
+from langgraph_sdk import get_sync_client
+from langgraph.graph import StateGraph, MessagesState, START
+from typing import TypedDict
+
+url = ""
+graph_name = "agent"
+remote_graph = RemoteGraph(graph_name, url=url)
+
+# define parent graph
+builder = StateGraph(MessagesState)
+# add remote graph directly as a node
+builder.add_node("child", remote_graph)
+builder.add_edge(START, "child")
+graph = builder.compile()
+
+# invoke the parent graph
+result = graph.invoke({
+ "messages": [{"role": "user", "content": "what's the weather in sf"}]
+})
+print(result)
+
+# stream outputs from both the parent graph and subgraph
+for chunk in graph.stream({
+ "messages": [{"role": "user", "content": "what's the weather in sf"}]
+}, subgraphs=True):
+ print(chunk)
+```
+
+```typescript JavaScript
+import { MessagesAnnotation, StateGraph, START } from "@langchain/langgraph";
+import { RemoteGraph } from "@langchain/langgraph/remote";
+
+const url = "";
+const graphName = "agent";
+const remoteGraph = new RemoteGraph({ graphId: graphName, url });
+
+// define parent graph and add remote graph directly as a node
+const graph = new StateGraph(MessagesAnnotation)
+ .addNode("child", remoteGraph)
+ .addEdge(START, "child")
+ .compile()
+
+// invoke the parent graph
+const result = await graph.invoke({
+ messages: [{ role: "user", content: "what's the weather in sf" }]
+});
+console.log(result);
+
+// stream outputs from both the parent graph and subgraph
+for await (const chunk of await graph.stream({
+ messages: [{ role: "user", content: "what's the weather in la" }]
+}, { subgraphs: true })) {
+ console.log(chunk);
+}
+```
+
+