---
title: start
description: Start and enqueue a new workflow run.
type: reference
summary: Use start to programmatically enqueue a new workflow run.
prerequisites:
  - /docs/foundations/starting-workflows
related:
  - /docs/foundations/idempotency
---

Start/enqueue a new workflow run.

```typescript lineNumbers
import { start } from "workflow/api";
import { myWorkflow } from "./workflows/my-workflow";

const run = await start(myWorkflow); // [!code highlight]
```

## API Signature

### Parameters

<TSDoc
definition={`
import { start } from "workflow/api";
export default start;`}
showSections={["parameters"]}
/>

#### StartOptions

<TSDoc
definition={`
import type { StartOptions } from "workflow/api";
export default StartOptions;`}
/>

### Returns

Returns a `Run` object:

<TSDoc
definition={`
import { Run } from "workflow/api";
export default Run;`}
showSections={["returns"]}
/>

Learn more about [`WorkflowReadableStreamOptions`](/docs/api-reference/workflow-api/get-run#workflowreadablestreamoptions).

## Good to Know

* The `start()` function is used in runtime contexts to programmatically trigger workflow executions.
* In v5, `start()` can also be called directly from a workflow function to spawn a child run or continue work in a new run. See [Workflow Composition](/cookbook/common-patterns/workflow-composition) and [Versioning](/docs/foundations/versioning).
* This is different from calling workflow functions directly, which is the typical pattern in Next.js applications.
* The function returns immediately after enqueuing the workflow - it doesn't wait for the workflow to complete.
* Each call to `start()` creates a new workflow run. If retried requests must route to one active workflow, have the workflow create a deterministic hook token and use [`getHookByToken()`](/docs/api-reference/workflow-api/get-hook-by-token) to reuse an already-registered active hook. The lookup is not atomic with `start()`, so concurrent callers can still create extra runs before the hook is registered; handle that race inside the workflow by checking `await hook.getConflict()` before duplicate-sensitive work — on a conflict it resolves with the run that owns the token, so the duplicate can return the active owner to the caller. If duplicates must be rejected before a workflow body runs, keep a durable request record until native atomic start-and-hook registration exists. See [Idempotency](/docs/foundations/idempotency#run-idempotency).
* All arguments must be [serializable](/docs/foundations/serialization).
* When `deploymentId` is provided, the argument types and return type become `unknown` since there is no guarantee the workflow function's types will be consistent across different deployments.
* `attributes` seeds plaintext run metadata as part of creation and requires a World implementing spec version 4 or later. Keys that start with `$` are reserved for framework and library code; framework-level callers can pass `allowReservedAttributes: true` to seed reserved keys, with the same semantics as the [`experimental_setAttributes`](/docs/api-reference/workflow/experimental-set-attributes) option of the same name.

<Callout type="info">
If `start()` throws `'start' received an invalid workflow function. Ensure the Workflow Development Kit is configured correctly and the function includes a 'use workflow' directive.`, the passed function was not transformed as a workflow. The two most common causes are a missing `"use workflow"` directive or missing framework integration. See [start-invalid-workflow-function](/docs/errors/start-invalid-workflow-function).
</Callout>

## Examples

### With Arguments

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

const run = await start(userSignupWorkflow, ["user@example.com"]); // [!code highlight]
```

### With `StartOptions`

```typescript
import { start } from "workflow/api";
import { myWorkflow } from "./workflows/my-workflow";

const run = await start(myWorkflow, ["arg1", "arg2"], { // [!code highlight]
  deploymentId: "custom-deployment-id", // [!code highlight]
  attributes: { source: "checkout" } // [!code highlight]
}); // [!code highlight]
```

### Using `deploymentId: "latest"`

Set `deploymentId` to `"latest"` to automatically resolve the most recent deployment for the current environment. This is useful when you want to ensure a workflow run targets the latest deployed version of your application rather than the deployment that initiated the call. For when to use this and how it fits with default run pinning, see [Versioning](/docs/foundations/versioning).

```typescript
import { start } from "workflow/api";
import { myWorkflow } from "./workflows/my-workflow";

const run = await start(myWorkflow, ["arg1", "arg2"], { // [!code highlight]
  deploymentId: "latest" // [!code highlight]
}); // [!code highlight]
```

<Callout type="info">
The `deploymentId` option is currently a Vercel-specific feature. Other Worlds may implement this option differently to match their own deployment runtimes, and the World spec may rename it from `deploymentId` to `version` in a future SDK version. On Vercel, `"latest"` resolves to the most recent deployment matching your current environment — the same production target for production deployments, or the same git branch for preview deployments.

In Worlds without atomic, immutable deployments (such as local development or self-hosted Postgres), there is no notion of multiple deployments to resolve between, so `deploymentId: "latest"` has no effect: the SDK logs a warning and the run targets the current deployment. This means a workflow that opts into `"latest"` on Vercel still runs unchanged in local development.
</Callout>

<Callout type="warn">
When using `deploymentId: "latest"`, the workflow run will execute on a potentially different deployment than the one calling `start()`. Be mindful of forward and backward compatibility:

- **Workflow identity**: The workflow ID is derived from the function name and file path. If the latest deployment has renamed the workflow function or moved it to a different directory, the workflow ID will no longer match and the run will fail to start.
- **Input and output compatibility**: The arguments passed to `start()` are serialized by the calling deployment but deserialized by the target deployment. Similarly, the workflow's return value is serialized by the target deployment but deserialized by the caller. If the workflow's expected arguments or return type have changed (e.g. added required fields, removed fields, or changed types), the run may fail or behave unexpectedly. Ensure that input and output schemas remain backward-compatible across deployments.
</Callout>
