---
title: Starting Workflows
description: Trigger workflow execution with the start() function and track progress with Run objects.
type: guide
summary: Trigger workflows and track their execution using the start() function.
prerequisites:
  - /docs/foundations/workflows-and-steps
related:
  - /docs/api-reference/workflow-api/start
---

Once you've defined your workflow functions, you need to trigger them to begin execution. This is done using the `start()` function from `workflow/api`, which enqueues a new workflow run and returns a `Run` object that you can use to track its progress.

## The `start()` Function

The [`start()`](/docs/api-reference/workflow-api/start) function is used to programmatically trigger workflow executions from runtime contexts like API routes, Server Actions, or any server-side code. In v5, you can also call `start()` from inside a workflow function when you want to spawn a child run or continue work in a new run.

```typescript lineNumbers
import { start } from "workflow/api";
import { handleUserSignup } from "./workflows/user-signup";

export async function POST(request: Request) {
  const { email } = await request.json();

  // Start the workflow
  const run = await start(handleUserSignup, [email]); // [!code highlight]

  return Response.json({
    message: "Workflow started",
    runId: run.runId
  });
}
```

**Key Points:**

- `start()` returns immediately after enqueuing the workflow - it doesn't wait for completion
- The first argument is your workflow function
- The second argument is an array of arguments to pass to the workflow (optional if the workflow takes no arguments)
- All arguments must be [serializable](/docs/foundations/serialization)

**Learn more**: [`start()` API Reference](/docs/api-reference/workflow-api/start)

<Callout type="info">
For parent-child workflow patterns, see [Workflow Composition](/cookbook/common-patterns/workflow-composition). For long-lived workflows that intentionally hand off to newer deployments with `deploymentId: "latest"`, see [Versioning](/docs/foundations/versioning).
</Callout>

## The `Run` Object

When you call `start()`, it returns a [`Run`](/docs/api-reference/workflow-api/start#returns) object that provides access to the workflow's status and results.

```typescript lineNumbers
import { start } from "workflow/api";
import { processOrder } from "./workflows/process-order";

const run = await start(processOrder, [/* orderId */]);

// The run object has properties you can await
console.log("Run ID:", run.runId);

// Check the workflow status
const status = await run.status; // "running" | "completed" | "failed"

// Get the workflow's return value (blocks until completion)
const result = await run.returnValue;
```

**Key Properties:**

- `runId` - Unique identifier for this workflow run
- `status` - Current status of the workflow (async)
- `returnValue` - The value returned by the workflow function (async, blocks until completion)
- `readable` - ReadableStream for streaming updates from the workflow

<Callout type="info">
Most `Run` properties are async getters that return promises. You need to `await` them to get their values. For a complete list of properties and methods, see the API reference below.
</Callout>

**Learn more**: [`Run` API Reference](/docs/api-reference/workflow-api/start#returns)

## Common Patterns

### Fire and Forget

The most common pattern is to start a workflow and immediately return, letting it execute in the background:

```typescript lineNumbers
import { start } from "workflow/api";
import { sendNotifications } from "./workflows/notifications";

export async function POST(request: Request) {
  // Start workflow and don't wait for it
  const run = await start(sendNotifications, [userId]);

  // Return immediately
  return Response.json({
    message: "Notifications queued",
    runId: run.runId
  });
}
```

### Wait for Completion

If you need to wait for the workflow to complete before responding:

```typescript lineNumbers
import { start } from "workflow/api";
import { generateReport } from "./workflows/reports";

export async function POST(request: Request) {
  const run = await start(generateReport, [reportId]);

  // Wait for the workflow to complete
  const report = await run.returnValue; // [!code highlight]

  return Response.json({ report });
}
```

<Callout type="warn">
Be cautious when waiting for `returnValue` - if your workflow takes a long time, your API route may timeout.
</Callout>

### Stream Updates to Client

Stream real-time updates from your workflow as it executes, without waiting for completion:

```typescript lineNumbers
import { start } from "workflow/api";
import { generateAIContent } from "./workflows/ai-generation";

export async function POST(request: Request) {
  const { prompt } = await request.json();

  // Start the workflow
  const run = await start(generateAIContent, [prompt]);

  // Get the readable stream (can also use run.readable as shorthand)
  const stream = run.getReadable(); // [!code highlight]

  // Return the stream immediately
  return new Response(stream, {
    headers: {
      "Content-Type": "application/octet-stream",
    },
  });
}
```

Your workflow can obtain a writable stream using [`getWritable()`](/docs/api-reference/workflow/get-writable):

```typescript lineNumbers
import { getWritable } from "workflow";

export async function generateAIContent(prompt: string) {
  "use workflow";

  const writable = getWritable(); // [!code highlight]

  await streamContentToClient(writable, prompt);

  return { status: "complete" };
}

async function streamContentToClient(
  writable: WritableStream,
  prompt: string
) {
  "use step";

  const writer = writable.getWriter();

  // Stream updates as they become available
  for (let i = 0; i < 10; i++) {
    const chunk = new TextEncoder().encode(`Update ${i}\n`);
    await writer.write(chunk);
  }

  writer.releaseLock();
}
```

<Callout type="info">
Streams are particularly useful for AI workflows where you want to show progress to users in real-time, or for long-running processes that produce intermediate results.
</Callout>

**Learn more**: [Streaming in Workflows](/docs/foundations/serialization#streaming)

### Check Status Later

You can retrieve a workflow run later using its `runId` with [`getRun()`](/docs/api-reference/workflow-api/get-run):

```typescript lineNumbers
import { getRun } from "workflow/api";

export async function GET(request: Request) {
  const url = new URL(request.url);
  const runId = url.searchParams.get("runId");

  // Retrieve the existing run
  const run = getRun(runId); // [!code highlight]

  // Check its status
  const status = await run.status;

  if (status === "completed") {
    const result = await run.returnValue;
    return Response.json({ result });
  }

  return Response.json({ status });
}
```

## Next Steps

Now that you understand how to start workflows and track their execution:

- Browse the [Cookbook](/cookbook) for copy-paste recipes covering composition, scheduling, timeouts, and more
- Explore [Errors & Retrying](/docs/foundations/errors-and-retries) to handle failures gracefully
- Check the [`start()` API Reference](/docs/api-reference/workflow-api/start) for complete details
