Ablauf

API Reference

Complete reference for the Ablauf class and related types

API Reference

Complete reference for the Ablauf class, its methods, and related types.

Ablauf Class

The main API for creating and managing workflows.

Constructor

new Ablauf(binding: DurableObjectNamespace, config?: AblaufConfig)

Parameters:

  • binding — The WORKFLOW_RUNNER Durable Object namespace from your worker's env
  • config — Optional configuration object

Config Options:

Prop

Type

Example:

import { Ablauf } from '@der-ablauf/workflows';
import { env } from 'cloudflare:workers';

const ablauf = new Ablauf(env.WORKFLOW_RUNNER, {
	workflows: [OrderWorkflow, [HighVolumeWorkflow, { shards: 8 }]],
	observability: true,
});

Methods

create()

Create and start a new workflow instance.

create<Payload, Result, Events extends object, Type extends string, SSEUpdates extends object>(
  workflow: WorkflowClass<Payload, Result, Events, Type, SSEUpdates>,
  props: { id: string; payload: Payload }
): Promise<WorkflowHandle<Payload, Result, Events, Type, SSEUpdates>>

Parameters:

  • workflow — The workflow class to instantiate
  • props.id — Workflow instance ID
  • props.payload — Input payload (validated against workflow's inputSchema)

Returns:

A WorkflowHandle for interacting with the workflow instance.

Throws:

  • PayloadValidationError — If payload validation fails
  • WorkflowAlreadyExistsError — If a workflow with the given ID already exists

Example:

const order = await ablauf.create(OrderWorkflow, {
  id: "order-123",
  payload: { orderId: "123", items: [...] },
});

const status = await order.getStatus();

get()

Get a handle for an existing workflow instance. This does not make a network call.

get<Payload, Result, Events extends object, Type extends string, SSEUpdates extends object>(
  workflow: WorkflowClass<Payload, Result, Events, Type, SSEUpdates>,
  props: { id: string }
): WorkflowHandle<Payload, Result, Events, Type, SSEUpdates>

Parameters:

  • workflow — The workflow class (for type inference and event schema)
  • props.id — Workflow instance ID

Returns:

A WorkflowHandle for interacting with the workflow instance.

Example:

const order = ablauf.get(OrderWorkflow, { id: 'order-123' });
const status = await order.getStatus();
await order.sendEvent({ event: 'payment', payload: { amount: 99 } });

list()

List workflow instances of a specific type.

list(
  type: string,
  filters?: WorkflowIndexListFilters
): Promise<WorkflowIndexEntry[]>

Parameters:

  • type — Workflow type (e.g., "process-order")
  • filters.status — Optional status filter
  • filters.limit — Optional result limit (sorted by updatedAt, newest first)

Throws:

  • ObservabilityDisabledError — If observability is disabled

Example:

const running = await ablauf.list('process-order', { status: 'running' });
const recent = await ablauf.list('process-order', { limit: 10 });

createWorkflowRunner()

Returns the Durable Object class to export from your worker.

createWorkflowRunner(overrides?: { binding?: string }): typeof WorkflowRunner

Example:

export const WorkflowRunner = ablauf.createWorkflowRunner();

createHandlers()

Returns oRPC handlers for the dashboard API (both RPC and OpenAPI).

createHandlers(): { rpcHandler: RPCHandler; openApiHandler: OpenAPIHandler }

Example:

const { rpcHandler, openApiHandler } = ablauf.createHandlers();

app.all('/__ablauf/*', async (c) => {
	const { matched, response } = await openApiHandler.handle(c.req.raw, {
		prefix: '/__ablauf',
		context: ablauf.getDashboardContext(),
	});
	if (matched) return c.newResponse(response.body, response);

	const { matched: matchedRpc, response: rpcResponse } = await rpcHandler.handle(c.req.raw, {
		prefix: '/__ablauf',
		context: ablauf.getDashboardContext(),
	});
	if (matchedRpc) return c.newResponse(rpcResponse.body, rpcResponse);

	return new Response('Not Found', { status: 404 });
});

WorkflowHandle

The WorkflowHandle is the primary interface for interacting with a specific workflow instance. You get a handle from ablauf.create() or ablauf.get().

getStatus()

Get the current status of this workflow instance.

getStatus(): Promise<WorkflowStatusResponseFor<Payload, Result, Type>>

Returns: A typed status response with inferred payload, result, and type.


sendEvent()

Send a typed event to this workflow instance.

sendEvent(props: WorkflowEventProps<Events>): Promise<void>

Parameters:

  • props.event — Event name
  • props.payload — Event payload (validated against event schema)

Throws:

  • EventValidationError — If event payload validation fails
  • WorkflowNotRunningError — If the workflow is not waiting for this event

Example:

const order = ablauf.get(OrderWorkflow, { id: 'order-123' });
await order.sendEvent({
	event: 'payment-received',
	payload: { amount: 99.99, transactionId: 'tx-456' },
});

pause()

Pause this workflow. It will finish its current step, then suspend.

pause(): Promise<void>

resume()

Resume this paused workflow. Replays execution history and continues from where it stopped.

resume(): Promise<void>

terminate()

Permanently terminate this workflow. It cannot be resumed after termination.

terminate(): Promise<void>

waitForUpdate()

Wait for a specific SSE update from this workflow.

waitForUpdate<K extends keyof SSEUpdates>(
  props: { update: K; timeout?: string }
): Promise<SSEUpdates[K]>

Parameters:

  • props.update — The SSE event name to wait for
  • props.timeout — Optional timeout as a duration string (e.g., "30s", "5m")

Throws:

  • UpdateTimeoutError — If the timeout expires before the update arrives
  • WorkflowNotRunningError — If the workflow completes or errors before the update

Example:

const order = ablauf.get(OrderWorkflow, { id: 'order-123' });
const progress = await order.waitForUpdate({
	update: 'progress',
	timeout: '30s',
});

Types

Step

The step API available inside workflow run() functions.

Prop

Type


SSE

The Server-Sent Events API available inside workflow run() functions.

Prop

Type


RetryConfig

Prop

Type


StepDoOptions

Options for step.do():

Prop

Type


StepWaitOptions

Options for step.waitForEvent():

Prop

Type


WorkflowStatus

type WorkflowStatus =
	| 'created' // Initial state after creation
	| 'running' // Actively executing steps
	| 'completed' // All steps finished successfully
	| 'errored' // A step or validation error occurred
	| 'paused' // Manually paused via pause()
	| 'sleeping' // Waiting for a step.sleep() or step.sleepUntil() timer
	| 'waiting' // Waiting for a step.waitForEvent() delivery
	| 'terminated'; // Permanently stopped via terminate()

WorkflowStatusResponse

Prop

Type


StepInfo

Prop

Type


WorkflowIndexEntry

Prop

Type


WorkflowIndexListFilters

Prop

Type


WorkflowShardConfig

Prop

Type


WorkflowClass

The interface that workflow definitions (both class-based and functional) must satisfy.

Prop

Type


Duration Strings

Ablauf uses human-readable duration strings in several places (e.g., step.sleep(), step.waitForEvent() timeout).

Supported Formats

FormatExampleDescription
Nms"500ms"Milliseconds
Ns"30s"Seconds
Nm"5m"Minutes
Nh"1h"Hours
Nd"7d"Days

Examples

await step.sleep('cooldown', '30s'); // 30 seconds
await step.sleep('backoff', '5m'); // 5 minutes
await step.sleep('daily', '1h'); // 1 hour

const result = await step.waitForEvent('payment-received', {
	timeout: '10m', // 10 minutes
});

Throws:

InvalidDurationError if the duration string is malformed.


Size Strings

Ablauf uses human-readable size strings for the resultSizeLimit.maxSize configuration.

Supported Formats

FormatExampleDescription
Nb"100b"Bytes
Nkb"512kb"Kilobytes
Nmb"64mb"Megabytes
Ngb"1gb"Gigabytes

Throws:

InvalidSizeError if the size string is malformed.


ResultSizeLimitConfig

Prop

Type


Error Classes

Engine Errors

All engine errors extend WorkflowError (which extends Error). Every engine error has a code, status, source, and message.

Error ClassCodeStatusSource
WorkflowNotFoundErrorWORKFLOW_NOT_FOUND404api
ResourceNotFoundErrorRESOURCE_NOT_FOUND404api
WorkflowAlreadyExistsErrorWORKFLOW_ALREADY_EXISTS409engine
WorkflowTypeUnknownErrorWORKFLOW_TYPE_UNKNOWN400api
PayloadValidationErrorVALIDATION_ERROR400validation
EventValidationErrorEVENT_INVALID400validation
StepFailedErrorSTEP_FAILED500step
StepRetryExhaustedErrorSTEP_RETRY_EXHAUSTED500step
EventTimeoutErrorEVENT_TIMEOUT408engine
UpdateTimeoutErrorUPDATE_TIMEOUT408engine
WorkflowNotRunningErrorWORKFLOW_NOT_RUNNING409engine
DuplicateStepErrorVALIDATION_ERROR400engine
InvalidDurationErrorVALIDATION_ERROR400validation
InvalidSizeErrorVALIDATION_ERROR400validation
ObservabilityDisabledErrorOBSERVABILITY_DISABLED400api
InvalidSchemaErrorINVALID_SCHEMA400validation

InvalidSchemaError

Thrown when a workflow schema uses Zod types that are not compatible with SuperJSON serialization. This error is raised at workflow registration time (not at runtime), catching invalid schemas early.

// This throws InvalidSchemaError because z.function() is not serializable:
defineWorkflow((t) => ({
	type: 'bad',
	input: z.object({ cb: z.function() }), // bypassed t namespace
	run: async () => ({}),
}));

The error message includes the full path to the unsupported type (e.g., "Unsupported Zod type "function" at path "input.cb").

See Supported Transport Types for the full list of allowed types.

NonRetriableError

NonRetriableError extends plain Error (not WorkflowError). It is a user-facing error designed to be thrown inside step.do() callbacks to signal that a failure is permanent and the step should not be retried.

import { NonRetriableError } from '@der-ablauf/workflows';

await step.do('validate-user', async () => {
	const user = await getUser(userId);
	if (user.banned) {
		throw new NonRetriableError('User is banned');
	}
	return user;
});

When thrown:

  1. The step is immediately marked as failed — no retries are attempted, regardless of retry configuration
  2. The error is recorded in the step's retry history
  3. The workflow transitions to errored

Use NonRetriableError for permanent failures where retrying would be wasteful: business rule violations, authorization failures, invalid data, or deleted resources.

See Skipping Retries with NonRetriableError for more details and examples.

Error JSON Shape

All WorkflowError instances serialize to:

{
	"error": {
		"code": "WORKFLOW_NOT_FOUND",
		"message": "Workflow \"order-123\" not found",
		"status": 404,
		"source": "api"
	}
}

Discriminating Errors

Across Durable Object RPC boundaries, errors lose their class identity. Use err.code to discriminate:

try {
	const order = ablauf.get(OrderWorkflow, { id: 'order-123' });
	await order.getStatus();
} catch (e) {
	if (e instanceof WorkflowError && e.code === 'WORKFLOW_NOT_FOUND') {
		// handle not found
	}
}

Transport Schema

The t namespace is a constrained subset of Zod that only exposes types compatible with SuperJSON serialization. It's provided as the parameter in defineWorkflow() callbacks and can be imported directly for BaseWorkflow usage.

import { t } from '@der-ablauf/workflows';

For wrapping pre-existing Zod schemas, use serializable():

import { serializable } from '@der-ablauf/workflows';
import { z } from 'zod';

const mySchema = serializable(z.object({ name: z.string() }));
// Throws InvalidSchemaError if schema uses unsupported types

See Supported Transport Types for the complete list of available types, excluded types, and migration guide.

On this page