Overview
start() initiates a new workflow execution and returns a Run object for tracking and interacting with the workflow. It handles argument serialization, event sourcing, and queuing the workflow for execution.
Usage
import { start } from 'workflow/runtime' ;
import { myWorkflow } from './workflows' ;
const run = await start ( myWorkflow , [ 'arg1' , 'arg2' ]);
console . log ( 'Started workflow:' , run . runId );
Signature
function start < TArgs extends unknown [], TResult >(
workflow : WorkflowFunction < TArgs , TResult > | WorkflowMetadata ,
args : TArgs ,
options ?: StartOptions
) : Promise < Run < TResult >>
function start < TResult >(
workflow : WorkflowFunction <[], TResult > | WorkflowMetadata ,
options ?: StartOptions
) : Promise < Run < TResult >>
Parameters
workflow
WorkflowFunction | WorkflowMetadata
required
The workflow function to start. Must have a 'use workflow' directive and be properly compiled.
Arguments to pass to the workflow function. Must be serializable.
Custom world instance to use. Defaults to getWorld().
Workflow spec version. Defaults to latest version. This is an advanced option. Only set if you need compatibility with specific spec versions.
Deployment ID for the workflow run. Auto-detected from environment. This should not be set in user code under normal circumstances.
Returns
A Run object for interacting with the workflow execution. See Run API .
Examples
Basic Workflow Start
import { start } from 'workflow/runtime' ;
import { processOrder } from './workflows/orders' ;
// Start a workflow with arguments
const run = await start ( processOrder , [{ orderId: '123' , items: [ ... ] }]);
// Wait for completion
const result = await run . returnValue ;
console . log ( 'Order processed:' , result );
No Arguments
import { start } from 'workflow/runtime' ;
import { dailyCleanup } from './workflows/maintenance' ;
// Start a workflow without arguments
const run = await start ( dailyCleanup );
console . log ( 'Cleanup started:' , run . runId );
With Options
import { start } from 'workflow/runtime' ;
import { createLocalWorld } from '@workflow/world-local' ;
import { dataProcessing } from './workflows' ;
// Use a custom world for testing
const testWorld = createLocalWorld ({ dataDir: './test-data' });
const run = await start (
dataProcessing ,
[{ dataset: 'test' }],
{ world: testWorld }
);
Start and Monitor
import { start } from 'workflow/runtime' ;
import { analyzeData } from './workflows' ;
const run = await start ( analyzeData , [ data ]);
// Check status periodically
const checkStatus = async () => {
const status = await run . status ;
console . log ( 'Current status:' , status );
if ( status === 'running' ) {
setTimeout ( checkStatus , 1000 );
}
};
checkStatus ();
Start and Stream Results
import { start } from 'workflow/runtime' ;
import { generateReport } from './workflows' ;
const run = await start ( generateReport , [ params ]);
// Stream results as they're generated
const reader = run . readable . getReader ();
while ( true ) {
const { done , value } = await reader . read ();
if ( done ) break ;
console . log ( 'Received chunk:' , value );
}
Parallel Workflow Starts
import { start } from 'workflow/runtime' ;
import { processItem } from './workflows' ;
// Start multiple workflows in parallel
const items = [ 1 , 2 , 3 , 4 , 5 ];
const runs = await Promise . all (
items . map ( item => start ( processItem , [ item ]))
);
console . log ( 'Started' , runs . length , 'workflows' );
// Wait for all to complete
const results = await Promise . all (
runs . map ( run => run . returnValue )
);
console . log ( 'All workflows completed:' , results );
Type-Safe Workflow Starts
import { start } from 'workflow/runtime' ;
// Workflow with typed arguments
export async function createUser ( name : string , email : string ) {
'use workflow' ;
// ... workflow implementation
return { userId: '123' , name , email };
}
// TypeScript ensures correct argument types
const run = await start ( createUser , [ 'John Doe' , '[email protected] ' ]);
// Return type is inferred
const user : { userId : string ; name : string ; email : string } = await run . returnValue ;
import { start } from 'workflow/runtime' ;
import { myWorkflow } from './workflows' ;
// Access workflow metadata (added by compiler)
const workflowId = ( myWorkflow as any ). workflowId ;
console . log ( 'Starting workflow:' , workflowId );
const run = await start ( myWorkflow , [ args ]);
Error Handling
import { start } from 'workflow/runtime' ;
import { WorkflowRuntimeError } from '@workflow/errors' ;
import { riskyWorkflow } from './workflows' ;
try {
const run = await start ( riskyWorkflow , [ params ]);
try {
const result = await run . returnValue ;
console . log ( 'Success:' , result );
} catch ( error ) {
// Workflow execution error
if ( error instanceof WorkflowRunFailedError ) {
console . error ( 'Workflow failed:' , error . message );
console . error ( 'Run ID:' , error . runId );
}
}
} catch ( error ) {
// Start error (e.g., invalid workflow, serialization error)
if ( WorkflowRuntimeError . is ( error )) {
console . error ( 'Failed to start workflow:' , error . message );
}
}
Run ID Generation
Each workflow run gets a unique ID in the format wrun_{ulid}. The ID is:
Generated client-side before execution
Globally unique and sortable by creation time
Used for tracking, logging, and event correlation
const run = await start ( myWorkflow , [ args ]);
console . log ( run . runId ); // e.g., "wrun_01HQXYZ123456789ABCDEFGH"
Serialization
Workflow arguments must be serializable. Supported types:
Primitives: string, number, boolean, null, undefined
Objects and arrays
Dates
URLs
Custom classes with proper serialization
Streams (automatically handled)
// ✅ Valid arguments
await start ( workflow , [
'string' ,
123 ,
{ nested: { object: true } },
new Date (),
new URL ( 'https://example.com' ),
]);
// ❌ Invalid arguments
await start ( workflow , [
function () {}, // Functions not serializable
Symbol ( 'test' ), // Symbols not serializable
]);
Trace Propagation
start() automatically propagates OpenTelemetry trace context to the workflow:
import { trace } from '@opentelemetry/api' ;
import { start } from 'workflow/runtime' ;
import { myWorkflow } from './workflows' ;
const tracer = trace . getTracer ( 'my-app' );
await tracer . startActiveSpan ( 'process-request' , async ( span ) => {
// Trace context automatically propagated to workflow
const run = await start ( myWorkflow , [ data ]);
span . setAttribute ( 'workflow.runId' , run . runId );
span . end ();
});
Best Practices
Await the start call : Always await start() to ensure the workflow is queued
Store run IDs : Save run.runId for later reference and monitoring
Use type inference : Let TypeScript infer return types from workflow functions
Handle start errors : Catch and handle errors from the start call separately from execution errors
Serialize carefully : Ensure all arguments are serializable before passing to workflows
Don’t start workflows from workflows : Use direct function calls or steps instead
See Also