# Run updates (backend)

> Source: https://trigger.dev/docs/realtime/backend/subscribe

**Subscribe to runs from your backend and get updates whenever status, metadata, or tags change.** Each function returns an async iterator that yields the run object on every change.

[​](https://trigger.dev/docs/realtime/backend/subscribe#runs-subscribetorun)

runs.subscribeToRun
---------------------------------------------------------------------------------------------------

Subscribes to all changes to a specific run.

Example

    import { runs } from "@trigger.dev/sdk";
    
    for await (const run of runs.subscribeToRun("run_1234")) {
      console.log(run);
    }
    

This function subscribes to all changes to a run. It returns an async iterator that yields the run object whenever the run is updated. The iterator will complete when the run is finished. **Authentication**: This function supports both server-side and client-side authentication. For server-side authentication, use your API key. For client-side authentication, you must generate a public access token with read access to the specific run. See our [authentication guide](https://trigger.dev/docs/realtime/auth)
 for details. **Response**: The AsyncIterator yields the [run object](https://trigger.dev/docs/realtime/run-object)
.

[​](https://trigger.dev/docs/realtime/backend/subscribe#runs-subscribetorunswithtag)

runs.subscribeToRunsWithTag
-------------------------------------------------------------------------------------------------------------------

Subscribes to all changes to runs with a specific tag.

Example

    import { runs } from "@trigger.dev/sdk";
    
    for await (const run of runs.subscribeToRunsWithTag("user:1234")) {
      console.log(run);
    }
    

This function subscribes to all changes to runs with a specific tag. It returns an async iterator that yields the run object whenever a run with the specified tag is updated. This iterator will never complete, so you must manually break out of the loop when you no longer want to receive updates. **Authentication**: This function supports both server-side and client-side authentication. For server-side authentication, use your API key. For client-side authentication, you must generate a public access token with read access to the specific tag. See our [authentication guide](https://trigger.dev/docs/realtime/auth)
 for details. **Response**: The AsyncIterator yields the [run object](https://trigger.dev/docs/realtime/run-object)
.

[​](https://trigger.dev/docs/realtime/backend/subscribe#runs-subscribetobatch)

runs.subscribeToBatch
-------------------------------------------------------------------------------------------------------

Subscribes to all changes for runs in a batch.

Example

    import { runs } from "@trigger.dev/sdk";
    
    for await (const run of runs.subscribeToBatch("batch_1234")) {
      console.log(run);
    }
    

This function subscribes to all changes for runs in a batch. It returns an async iterator that yields a run object whenever a run in the batch is updated. The iterator does not complete on its own, you must manually `break` the loop when you want to stop listening for updates. **Authentication**: This function supports both server-side and client-side authentication. For server-side authentication, use your API key. For client-side authentication, you must generate a public access token with read access to the specific batch. See our [authentication guide](https://trigger.dev/docs/realtime/auth)
 for details. **Response**: The AsyncIterator yields the [run object](https://trigger.dev/docs/realtime/run-object)
.

[​](https://trigger.dev/docs/realtime/backend/subscribe#type-safety)

Type safety
-----------------------------------------------------------------------------------

You can infer the types of the run’s payload and output by passing the type of the task to the subscribe functions:

    import { runs, tasks } from "@trigger.dev/sdk";
    import type { myTask } from "./trigger/my-task";
    
    async function myBackend() {
      const handle = await tasks.trigger("my-task", { some: "data" });
    
      for await (const run of runs.subscribeToRun<typeof myTask>(handle.id)) {
        // run.payload and run.output are now typed
        console.log(run.payload.some);
    
        if (run.output) {
          console.log(run.output.some);
        }
      }
    }
    

When using `subscribeToRunsWithTag`, you can pass a union of task types:

    import { runs } from "@trigger.dev/sdk";
    import type { myTask, myOtherTask } from "./trigger/my-task";
    
    for await (const run of runs.subscribeToRunsWithTag<typeof myTask | typeof myOtherTask>("my-tag")) {
      // Narrow down the type based on the taskIdentifier
      switch (run.taskIdentifier) {
        case "my-task": {
          console.log("Run output:", run.output.foo); // Type-safe
          break;
        }
        case "my-other-task": {
          console.log("Run output:", run.output.bar); // Type-safe
          break;
        }
      }
    }
    

[​](https://trigger.dev/docs/realtime/backend/subscribe#subscribe-to-metadata-updates-from-your-tasks)

Subscribe to metadata updates from your tasks
-------------------------------------------------------------------------------------------------------------------------------------------------------

The metadata API allows you to update custom metadata on runs and receive real-time updates when metadata changes. This is useful for tracking progress, storing intermediate results, or adding custom status information that can be monitored in real-time.

For frontend applications using React, see our [React hooks metadata documentation](https://trigger.dev/docs/realtime/react-hooks/subscribe#using-metadata-to-show-progress-in-your-ui)
 for consuming metadata updates in your UI.

When you update metadata from within a task using `metadata.set()`, `metadata.append()`, or other metadata methods, all subscribers to that run will automatically receive the updated run object containing the new metadata. This makes metadata perfect for:

*   Progress tracking
*   Status updates
*   Intermediate results
*   Custom notifications

Use the metadata API within your task to update metadata in real-time. In this basic example task, we’re updating the progress of a task as it processes items.

### 

[​](https://trigger.dev/docs/realtime/backend/subscribe#how-to-subscribe-to-metadata-updates)

How to subscribe to metadata updates

This example task updates the progress of a task as it processes items.

    // Your task code
    import { task, metadata } from "@trigger.dev/sdk";
    
    export const progressTask = task({
      id: "progress-task",
      run: async (payload: { items: string[] }) => {
        const total = payload.items.length;
    
        for (let i = 0; i < payload.items.length; i++) {
          // Update progress metadata
          metadata.set("progress", {
            current: i + 1,
            total: total,
            percentage: Math.round(((i + 1) / total) * 100),
            currentItem: payload.items[i],
          });
    
          // Process the item
          await processItem(payload.items[i]);
        }
    
        metadata.set("status", "completed");
        return { processed: total };
      },
    });
    
    async function processItem(item: string) {
      // Simulate work
      await new Promise((resolve) => setTimeout(resolve, 1000));
    }
    

We can now subscribe to the runs and receive real-time metadata updates.

    // Somewhere in your backend code
    import { runs } from "@trigger.dev/sdk";
    import type { progressTask } from "./trigger/progress-task";
    
    async function monitorProgress(runId: string) {
      for await (const run of runs.subscribeToRun<typeof progressTask>(runId)) {
        console.log(`Run ${run.id} status: ${run.status}`);
    
        if (run.metadata?.progress) {
          const progress = run.metadata.progress as {
            current: number;
            total: number;
            percentage: number;
            currentItem: string;
          };
    
          console.log(`Progress: ${progress.current}/${progress.total} (${progress.percentage}%)`);
          console.log(`Processing: ${progress.currentItem}`);
        }
    
        if (run.metadata?.status === "completed") {
          console.log("Task completed!");
          break;
        }
      }
    }
    

For more information on how to write tasks that use the metadata API, as well as more examples, see our [run metadata docs](https://trigger.dev/docs/runs/metadata#more-metadata-task-examples)
.

### 

[​](https://trigger.dev/docs/realtime/backend/subscribe#type-safety-2)

Type safety

You can get type safety for your metadata by defining types:

    import { runs } from "@trigger.dev/sdk";
    import type { progressTask } from "./trigger/progress-task";
    
    interface ProgressMetadata {
      progress?: {
        current: number;
        total: number;
        percentage: number;
        currentItem: string;
      };
      status?: "running" | "completed" | "failed";
    }
    
    async function monitorTypedProgress(runId: string) {
      for await (const run of runs.subscribeToRun<typeof progressTask>(runId)) {
        const metadata = run.metadata as ProgressMetadata;
    
        if (metadata?.progress) {
          // Now you have full type safety
          console.log(`Progress: ${metadata.progress.percentage}%`);
        }
      }
    }
    

Was this page helpful?

YesNo

[Previous](https://trigger.dev/docs/realtime/backend/overview)
[StreamingRead AI/LLM output, file chunks, and other streaming data from your Trigger.dev tasks in backend code.\
\
Next](https://trigger.dev/docs/realtime/backend/streams)

Ctrl+I

Assistant

Responses are generated using AI and may contain mistakes.
