How to Use `useTamboThreadList` and `useTamboThread` Hooks in Tambo AI

The useTamboThreadList and useTamboThread hooks from the @tambo-ai/react SDK provide React-Query-style data fetching for conversation threads, returning loading states, cached data, and error handling while automatically managing context keys and API authentication.

The tambo-ai/tambo repository provides a comprehensive React SDK that abstracts thread management into composable hooks. When building AI chat interfaces with Tambo AI, understanding how to leverage useTamboThreadList for fetching thread catalogs and useTamboThread for retrieving individual conversation histories is essential for performant, type-safe applications.

Understanding the Tambo AI Thread Hooks Architecture

The React SDK implements a layered architecture where hooks consume context from the TamboStreamProvider and interact with the Tambo AI backend API at /api/v1/threads.

The TamboStreamProvider Context Layer

At react-sdk/src/v1/providers/tambo-v1-stream-context.tsx, the TamboStreamProvider maintains the current thread ID and streaming state. All thread-related hooks—including useTamboThreadList, useTamboThread, and useThreadManagement—must be used within this provider to access the shared context and authentication headers.

Thread List vs. Single Thread Data Flow

The useTamboThreadList hook (located at react-sdk/src/v1/hooks/use-tambo-v1-thread-list.ts) fetches the complete thread catalog via an internal fetcher utility. It automatically injects the projectId and userKey from the provider context unless explicitly overridden.

The useTamboThread hook (at react-sdk/src/v1/hooks/use-tambo-v1-thread.ts) implements a caching optimization: it first attempts to extract the requested thread from the list cache populated by useTamboThreadList. Only if the thread is missing does it trigger a fresh fetch, minimizing redundant network requests.

Fetching Thread Lists with useTamboThreadList

The useTamboThreadList hook returns a React-Query-style result object containing data, isLoading, isError, and refetch properties. This pattern enables declarative UI rendering based on fetch state.

In react-sdk/src/v1/hooks/use-tambo-v1-thread-list.ts, the hook constructs the API request using the context key from TamboStreamProvider, ensuring authenticated access to the /api/v1/threads endpoint.

import { useTamboThreadList } from "@tambo-ai/react";

export function ThreadList() {
  const {
    data: threads,
    isLoading,
    isError,
    refetch,
  } = useTamboThreadList();

  if (isLoading) return <p>Loading threads…</p>;
  if (isError) return <p>Failed to load threads. <button onClick={() => refetch()}>Retry</button></p>;

  return (
    <ul>
      {threads?.threads.map((t) => (
        <li key={t.id}>{t.name}</li>
      ))}
    </ul>
  );
}

Retrieving Individual Threads with useTamboThread

When you need to display a specific conversation history, useTamboThread accepts a threadId string and returns the corresponding thread object, including its message array.

As implemented in react-sdk/src/v1/hooks/use-tambo-v1-thread.ts, this hook leverages the SWR-style caching from useTamboThreadList. If the thread exists in the cached list data, it returns immediately without an additional network request.

import { useTamboThread } from "@tambo-ai/react";

export function ThreadViewer({ threadId }: { threadId: string }) {
  const { data: thread, isLoading } = useTamboThread(threadId);

  if (isLoading) return <p>Loading thread…</p>;
  if (!thread) return <p>No thread found.</p>;

  return (
    <div>
      <h2>{thread.name}</h2>
      <ul>
        {thread.messages.map((msg) => (
          <li key={msg.id}>
            <strong>{msg.role}:</strong> {msg.content}
          </li>
        ))}
      </ul>
    </div>
  );
}

Managing Thread State with useThreadManagement

Navigation between threads and thread creation is handled by the useThreadManagement hook, defined in react-sdk/src/v1/providers/tambo-v1-stream-context.tsx. This hook must be used inside a TamboStreamProvider and provides imperative actions to modify the current thread state.

Switching Between Existing Threads

The switchThread(threadId) function updates the provider's currentThreadId state. This change propagates to all dependent hooks, causing useTamboThread and message-related hooks to re-render with the new thread's data.

import {
  useTamboThreadList,
  useThreadManagement,
} from "@tambo-ai/react";

export function ThreadSwitcher() {
  const { data } = useTamboThreadList();
  const { switchThread } = useThreadManagement();

  return (
    <select
      onChange={(e) => switchThread(e.target.value)}
      defaultValue=""
    >
      <option value="" disabled>
        Select a thread…
      </option>
      {data?.threads.map((t) => (
        <option key={t.id} value={t.id}>
          {t.name}
        </option>
      ))}
    </select>
  );
}

Creating New Threads Programmatically

The startNewThread() function initiates a fresh conversation by calling the Tambo AI API to create a new thread, then automatically selects it as the current thread.

import { useThreadManagement } from "@tambo-ai/react";

export function NewThreadButton() {
  const { startNewThread } = useThreadManagement();

  return <button onClick={startNewThread}>New Thread</button>;
}

Complete Integration Example

Combining these hooks creates a fully functional thread management interface. The following example demonstrates the composition pattern used in the SDK's own UI components like ThreadDropdown and ThreadHistory (located in packages/ui-registry/src/components/).

import {
  TamboProvider,
  TamboStreamProvider,
  useTamboThreadList,
  useTamboThread,
  useThreadManagement,
} from "@tambo-ai/react";

function ThreadManager() {
  const { data: listData, isLoading: listLoading } = useTamboThreadList();
  const { currentThreadId, switchThread, startNewThread } = useThreadManagement();
  const { data: currentThread } = useTamboThread(currentThreadId);

  if (listLoading) return <div>Loading threads...</div>;

  return (
    <div>
      <div className="thread-list">
        <button onClick={startNewThread}>+ New Thread</button>
        <ul>
          {listData?.threads.map((thread) => (
            <li 
              key={thread.id}
              onClick={() => switchThread(thread.id)}
              className={currentThreadId === thread.id ? 'active' : ''}
            >
              {thread.name}
            </li>
          ))}
        </ul>
      </div>
      
      <div className="thread-content">
        {currentThread ? (
          <div>
            <h2>{currentThread.name}</h2>
            <div className="messages">
              {currentThread.messages.map((msg) => (
                <div key={msg.id} className={`message ${msg.role}`}>
                  {msg.content}
                </div>
              ))}
            </div>
          </div>
        ) : (
          <p>Select a thread to view messages</p>
        )}
      </div>
    </div>
  );
}

export default function App() {
  return (
    <TamboProvider apiKey={process.env.TAMBO_API_KEY}>
      <TamboStreamProvider>
        <ThreadManager />
      </TamboStreamProvider>
    </TamboProvider>
  );
}

Summary

  • useTamboThreadList fetches the complete thread catalog from /api/v1/threads, returning a React-Query-style object with data, isLoading, isError, and refetch properties.

  • useTamboThread retrieves a single thread by ID, intelligently caching data from useTamboThreadList to avoid redundant network requests when the thread already exists in the list cache.

  • useThreadManagement provides imperative actions (switchThread and startNewThread) to navigate between conversations and create new ones, but requires wrapping components in TamboStreamProvider.

  • All hooks automatically handle authentication by reading the projectId and userKey from the TamboStreamProvider context, eliminating manual header management.

  • The hooks are implemented in react-sdk/src/v1/hooks/ and exported through react-sdk/src/v1/hooks/use-tambo-v1.ts for public consumption.

Frequently Asked Questions

What is the difference between useTamboThreadList and useTamboThread?

useTamboThreadList fetches the entire catalog of threads for the current user or project from the /api/v1/threads endpoint, returning an array of thread metadata. In contrast, useTamboThread accepts a specific threadId parameter and returns the full thread object including its message history. Additionally, useTamboThread implements a caching optimization where it first checks the existing cache from useTamboThreadList before making a new network request.

How does useTamboThread handle caching?

According to the implementation in react-sdk/src/v1/hooks/use-tambo-v1-thread.ts, the hook first attempts to extract the requested thread from the cache populated by useTamboThreadList. If the thread exists in the list data already loaded in memory, it returns immediately without triggering an additional HTTP request. Only when the thread is missing from the cache does it initiate a fresh fetch, minimizing network overhead and improving UI responsiveness when switching between recently loaded threads.

Can I use these hooks outside of TamboStreamProvider?

No, both useTamboThreadList and useTamboThread depend on the context provided by TamboStreamProvider (defined in react-sdk/src/v1/providers/tambo-v1-stream-context.tsx). The provider supplies the necessary authentication context (projectId and userKey) and the current thread state. Attempting to use these hooks outside the provider will result in runtime errors due to missing context. You must wrap your component tree with both TamboProvider (for API configuration) and TamboStreamProvider (for thread state management).

How do I create a new thread programmatically?

To create a new thread programmatically, use the useThreadManagement hook exported from @tambo-ai/react. This hook provides a startNewThread() function that calls the Tambo AI API to create a new thread and automatically updates the provider's currentThreadId to select the newly created thread. Unlike useTamboThreadList and useTamboThread, useThreadManagement is defined in react-sdk/src/v1/providers/tambo-v1-stream-context.tsx and provides imperative actions rather than data fetching capabilities.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →