Documents
langgraph
langgraph
Type
External
Status
Published
Created
Mar 17, 2026
Updated
Mar 17, 2026

Overview#

This guide shows how to integrate Assistant Cloud with LangGraph Cloud using assistant-ui's runtime system and pre-built UI components.

Prerequisites#

You need an assistant-cloud account to follow this guide. [Sign up here](https://cloud.assistant-ui.com/) to get started.

Setup Guide#

Create a Cloud Project#

Create a new project in the assistant-cloud dashboard and from the settings page, copy:

  • Frontend API URL: https://proj-[ID].assistant-api.com
  • API Key: For server-side operations

Configure Environment Variables#

Add the following environment variables to your project:

# Frontend API URL from your cloud project settings
NEXT_PUBLIC_ASSISTANT_BASE_URL=https://proj-[YOUR-ID].assistant-api.com

# API key for server-side operations
ASSISTANT_API_KEY=your-api-key-here

Install Dependencies#

Install the required packages:

<InstallCommand npm={["@assistant-ui/react", "@assistant-ui/react-langgraph"]} />

Create the Runtime Provider#

Create a runtime provider that integrates LangGraph with assistant-cloud. Choose between anonymous mode for demos/prototypes or authenticated mode for production:

<Tabs items={["Anonymous", "Authenticated (Clerk)"]}>

"use client";

import {
  AssistantCloud,
  AssistantRuntimeProvider,
} from "@assistant-ui/react";
import { useLangGraphRuntime } from "@assistant-ui/react-langgraph";
import { createThread, deleteThread, getThreadState, sendMessage } from "@/lib/chatApi";
import { LangChainMessage } from "@assistant-ui/react-langgraph";
import { useMemo } from "react";

export function MyRuntimeProvider({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  const cloud = useMemo(
    () =>
      new AssistantCloud({
        baseUrl: process.env.NEXT_PUBLIC_ASSISTANT_BASE_URL!,
        anonymous: true, // Creates browser session-based user ID
      }),
    [],
  );

  const runtime = useLangGraphRuntime({
    cloud,
    stream: async function* (messages, { initialize }) {
      const { externalId } = await initialize();
      if (!externalId) throw new Error("Thread not found");

      return sendMessage({
        threadId: externalId,
        messages,
      });
    },
    create: async () => {
      const { thread_id } = await createThread();
      return { externalId: thread_id };
    },
    load: async (externalId) => {
      const state = await getThreadState(externalId);
      return {
        messages:
          (state.values as { messages?: LangChainMessage[] }).messages ?? [],
      };
    },
    delete: async (externalId) => {
      await deleteThread(externalId);
    },
  });

  return (
    <AssistantRuntimeProvider runtime={runtime}>
      {children}
    </AssistantRuntimeProvider>
  );
}
"use client";

import {
  AssistantCloud,
  AssistantRuntimeProvider,
} from "@assistant-ui/react";
import { useLangGraphRuntime } from "@assistant-ui/react-langgraph";
import { createThread, deleteThread, getThreadState, sendMessage } from "@/lib/chatApi";
import { LangChainMessage } from "@assistant-ui/react-langgraph";
import { useAuth } from "@clerk/nextjs";
import { useMemo } from "react";

export function MyRuntimeProvider({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  const { getToken } = useAuth();

  const cloud = useMemo(
    () =>
      new AssistantCloud({
        baseUrl: process.env.NEXT_PUBLIC_ASSISTANT_BASE_URL!,
        authToken: async () => getToken({ template: "assistant-ui" }),
      }),
    [getToken],
  );

  const runtime = useLangGraphRuntime({
    cloud,
    stream: async function* (messages, { initialize }) {
      const { externalId } = await initialize();
      if (!externalId) throw new Error("Thread not found");

      return sendMessage({
        threadId: externalId,
        messages,
      });
    },
    create: async () => {
      const { thread_id } = await createThread();
      return { externalId: thread_id };
    },
    load: async (externalId) => {
      const state = await getThreadState(externalId);
      return {
        messages:
          (state.values as { messages?: LangChainMessage[] }).messages ?? [],
      };
    },
    delete: async (externalId) => {
      await deleteThread(externalId);
    },
  });

  return (
    <AssistantRuntimeProvider runtime={runtime}>
      {children}
    </AssistantRuntimeProvider>
  );
}
For Clerk authentication, configure the `"assistant-ui"` token template in your Clerk dashboard. The `useLangGraphRuntime` hook accepts `cloud`, `create`, `load`, and `delete` parameters for simplified thread management. The runtime handles the thread lifecycle internally.
  • create: Called when creating a new thread. Returns { externalId } with your backend's thread ID.
  • load: Called when switching to an existing thread. Returns the thread's messages (and optionally interrupts).
  • delete: Called when deleting a thread. Receives the thread's externalId. When provided, users can delete threads from the thread list UI.

Add Thread UI Components#

Install the thread list component:

<Tabs items={["assistant-ui", "shadcn (namespace)", "shadcn"]}>

npx assistant-ui@latest add thread-list
npx shadcn@latest add https://r.assistant-ui.com/thread-list.json
npx shadcn@latest add https://r.assistant-ui.com/thread-list.json

Then add it to your application layout:

import { Thread } from "@/components/assistant-ui/thread";
import { ThreadList } from "@/components/assistant-ui/thread-list";

export default function ChatPage() {
  return (
    <div className="grid h-dvh grid-cols-[250px_1fr] gap-x-2">
      <ThreadList />
      <Thread />
    </div>
  );
}

Authentication#

The examples above show two authentication modes:

  • Anonymous: Suitable for demos and prototypes. Creates a browser session-based user ID.
  • Authenticated: For production use with user accounts. The authenticated example uses Clerk, but you can integrate any auth provider.

For other authentication providers or custom implementations, see the Cloud Authorization guide.

Next Steps#