Our react hooks package provides a set of hooks that make it easy to interact with the Trigger.dev API from your React application, using our frontend API. You can use these hooks to fetch runs, batches, and subscribe to real-time updates.
Installation
Install the @trigger.dev/react-hooks
package in your project:
Authentication
Before you can use the hooks, you need to provide a public access token to the TriggerAuthContext
provider. Learn more about authentication in the frontend guide.
import { TriggerAuthContext } from "@trigger.dev/react-hooks";
export function SetupTrigger() {
return (
<TriggerAuthContext.Provider value={{ accessToken: "your-access-token" }}>
<MyComponent />
</TriggerAuthContext.Provider>
);
}
Now children components can use the hooks to interact with the Trigger.dev API. If you are self-hosting Trigger.dev, you can provide the baseURL
to the TriggerAuthContext
provider.
import { TriggerAuthContext } from "@trigger.dev/react-hooks";
export function SetupTrigger() {
return (
<TriggerAuthContext.Provider
value={{
accessToken: "your-access-token",
baseURL: "https://your-trigger-dev-instance.com",
}}
>
<MyComponent />
</TriggerAuthContext.Provider>
);
}
Next.js and client components
If you are using Next.js with the App Router, you have to make sure the component that uses the TriggerAuthContext
is a client component. So for example, the following code will not work:
import { TriggerAuthContext } from "@trigger.dev/react-hooks";
export default function Page() {
return (
<TriggerAuthContext.Provider value={{ accessToken: "your-access-token" }}>
<MyComponent />
</TriggerAuthContext.Provider>
);
}
That’s because Page
is a server component and the TriggerAuthContext.Provider
uses client-only react code. To fix this, wrap the TriggerAuthContext.Provider
in a client component:
components/TriggerProvider.tsx
"use client";
import { TriggerAuthContext } from "@trigger.dev/react-hooks";
export function TriggerProvider({
accessToken,
children,
}: {
accessToken: string;
children: React.ReactNode;
}) {
return (
<TriggerAuthContext.Provider
value={{
accessToken,
}}
>
{children}
</TriggerAuthContext.Provider>
);
}
Passing the token to the frontend
Techniques for passing the token to the frontend vary depending on your setup. Here are a few ways to do it for different setups:
Next.js App Router
If you are using Next.js with the App Router and you are triggering a task from a server action, you can use cookies to store and pass the token to the frontend.
"use server";
import { tasks } from "@trigger.dev/sdk/v3";
import type { exampleTask } from "@/trigger/example";
import { redirect } from "next/navigation";
import { cookies } from "next/headers";
export async function startRun() {
const handle = await tasks.trigger<typeof exampleTask>("example", { foo: "bar" });
cookies().set("publicAccessToken", handle.publicAccessToken);
redirect(`/runs/${handle.id}`);
}
Then in the /runs/[id].tsx
page, you can read the token from the cookie and pass it to the TriggerProvider
.
import { TriggerProvider } from "@/components/TriggerProvider";
export default function RunPage({ params }: { params: { id: string } }) {
const publicAccessToken = cookies().get("publicAccessToken");
return (
<TriggerProvider accessToken={publicAccessToken}>
<RunDetails id={params.id} />
</TriggerProvider>
);
}
Instead of a cookie, you could also use a query parameter to pass the token to the frontend:
import { tasks } from "@trigger.dev/sdk/v3";
import type { exampleTask } from "@/trigger/example";
import { redirect } from "next/navigation";
import { cookies } from "next/headers";
export async function startRun() {
const handle = await tasks.trigger<typeof exampleTask>("example", { foo: "bar" });
redirect(`/runs/${handle.id}?publicAccessToken=${handle.publicAccessToken}`);
}
And then in the /runs/[id].tsx
page:
import { TriggerProvider } from "@/components/TriggerProvider";
export default function RunPage({
params,
searchParams,
}: {
params: { id: string };
searchParams: { publicAccessToken: string };
}) {
return (
<TriggerProvider accessToken={searchParams.publicAccessToken}>
<RunDetails id={params.id} />
</TriggerProvider>
);
}
Another alternative would be to use a server-side rendered page to fetch the token and pass it to the frontend:
Usage
SWR vs Realtime hooks
We offer two “styles” of hooks: SWR and Realtime. The SWR hooks use the swr library to fetch data once and cache it. The Realtime hooks use Trigger.dev realtime to subscribe to updates in real-time.
It can be a little confusing which one to use because swr can also be
configured to poll for updates. But because of rate-limits and the way the Trigger.dev API works,
we recommend using the Realtime hooks for most use-cases.
All hooks named useRealtime*
are Realtime hooks, and all hooks named use*
are SWR hooks.
Common SWR hook options
You can pass the following options to the all SWR hooks:
Revalidate the data when the window regains focus.
Revalidate the data when the browser regains a network connection.
Poll for updates at the specified interval (in milliseconds). Polling is not recommended for most
use-cases. Use the Realtime hooks instead.
Common SWR hook return values
An error object if an error occurred while fetching the data.
A boolean indicating if the data is currently being fetched.
A boolean indicating if the data is currently being revalidated.
A boolean indicating if an error occurred while fetching the data.
useRun
The useRun
hook allows you to fetch a run by its ID.
"use client";
import { useRun } from "@trigger.dev/react-hooks";
export function MyComponent({ runId }: { runId: string }) {
const { run, error, isLoading } = useRun(runId);
if (isLoading) return <div>Loading...</div>;
if (error) return <div>Error: {error.message}</div>;
return <div>Run: {run.id}</div>;
}
The run
object returned is the same as the run object returned by the Trigger.dev API. To correctly type the run’s payload and output, you can provide the type of your task to the useRun
hook:
import { useRun } from "@trigger.dev/react-hooks";
import type { myTask } from "@/trigger/myTask";
export function MyComponent({ runId }: { runId: string }) {
const { run, error, isLoading } = useRun<typeof myTask>(runId);
if (isLoading) return <div>Loading...</div>;
if (error) return <div>Error: {error.message}</div>;
return <div>Run: {run.id}</div>;
}
useRealtimeRun
The useRealtimeRun
hook allows you to subscribe to a run by its ID.
"use client";
import { useRealtimeRun } from "@trigger.dev/react-hooks";
export function MyComponent({ runId }: { runId: string }) {
const { run, error } = useRealtimeRun(runId);
if (error) return <div>Error: {error.message}</div>;
return <div>Run: {run.id}</div>;
}
To correctly type the run’s payload and output, you can provide the type of your task to the useRealtimeRun
hook:
import { useRealtimeRun } from "@trigger.dev/react-hooks";
import type { myTask } from "@/trigger/myTask";
export function MyComponent({ runId }: { runId: string }) {
const { run, error } = useRealtimeRun<typeof myTask>(runId);
if (error) return <div>Error: {error.message}</div>;
return <div>Run: {run.id}</div>;
}
See our Realtime documentation for more information.
useRealtimeRunsWithTag
The useRealtimeRunsWithTag
hook allows you to subscribe to multiple runs with a specific tag.
"use client";
import { useRealtimeRunsWithTag } from "@trigger.dev/react-hooks";
export function MyComponent({ tag }: { tag: string }) {
const { runs, error } = useRealtimeRunsWithTag(tag);
if (error) return <div>Error: {error.message}</div>;
return (
<div>
{runs.map((run) => (
<div key={run.id}>Run: {run.id}</div>
))}
</div>
);
}
To correctly type the runs payload and output, you can provide the type of your task to the useRealtimeRunsWithTag
hook:
import { useRealtimeRunsWithTag } from "@trigger.dev/react-hooks";
import type { myTask } from "@/trigger/myTask";
export function MyComponent({ tag }: { tag: string }) {
const { runs, error } = useRealtimeRunsWithTag<typeof myTask>(tag);
if (error) return <div>Error: {error.message}</div>;
return (
<div>
{runs.map((run) => (
<div key={run.id}>Run: {run.id}</div>
))}
</div>
);
}
If useRealtimeRunsWithTag
could return multiple different types of tasks, you can pass a union of all the task types to the hook:
import { useRealtimeRunsWithTag } from "@trigger.dev/react-hooks";
import type { myTask1, myTask2 } from "@/trigger/myTasks";
export function MyComponent({ tag }: { tag: string }) {
const { runs, error } = useRealtimeRunsWithTag<typeof myTask1 | typeof myTask2>(tag);
if (error) return <div>Error: {error.message}</div>;
for (const run of runs) {
if (run.taskIdentifier === "my-task-1") {
} else if (run.taskIdentifier === "my-task-2") {
}
}
return (
<div>
{runs.map((run) => (
<div key={run.id}>Run: {run.id}</div>
))}
</div>
);
}
See our Realtime documentation for more information.
useRealtimeBatch
The useRealtimeBatch
hook allows you to subscribe to a batch of runs by its the batch ID.
"use client";
import { useRealtimeBatch } from "@trigger.dev/react-hooks";
export function MyComponent({ batchId }: { batchId: string }) {
const { runs, error } = useRealtimeBatch(batchId);
if (error) return <div>Error: {error.message}</div>;
return (
<div>
{runs.map((run) => (
<div key={run.id}>Run: {run.id}</div>
))}
</div>
);
}
See our Realtime documentation for more information.