Ploy
Features

Workflows

Build durable, multi-step workflows with automatic retries and state persistence.

Workflows

Ploy Workflows let you define long-running, multi-step processes that survive failures. Each step is durably persisted and automatically retried on errors.

Configuration

Add a workflow binding in your ploy.yaml:

ploy.yaml
kind: worker
build: pnpm build
out: dist
workflow:
  ORDER_FLOW: order_processing

The key (ORDER_FLOW) is the binding name. The value (order_processing) must match the workflow function name in your code.

Run ploy types to generate TypeScript types:

env.d.ts
import type { WorkflowBinding } from "@meetploy/types";

export interface Env {
	ORDER_FLOW: WorkflowBinding;
}

Basic Example

src/index.ts
import type { Env } from "./env.js";
import type { Ploy, WorkflowContext } from "@meetploy/types";

export default {
	async fetch(request, env) {
		// Trigger a workflow execution
		const { executionId } = await env.ORDER_FLOW.trigger({
			orderId: "123",
			amount: 99.99,
		});

		return Response.json({ executionId });
	},

	workflows: {
		async order_processing({
			input,
			step,
		}: WorkflowContext<Env, { orderId: string; amount: number }>) {
			// Step 1: Validate
			const order = await step.run("validate", async () => {
				return { valid: true, orderId: input.orderId };
			});

			// Step 2: Charge payment
			const payment = await step.run("charge", async () => {
				return { paymentId: `pay_${Date.now()}` };
			});

			// Step 3: Fulfill
			const fulfillment = await step.run("fulfill", async () => {
				return { trackingNumber: `TRACK_${Date.now()}` };
			});

			return { orderId: order.orderId, paymentId: payment.paymentId };
		},
	},
} satisfies Ploy<Env>;

Workflow Binding API

Trigger

Start a new workflow execution:

const { executionId } = await env.ORDER_FLOW.trigger({ orderId: "123" });

Get Status

Check execution status:

const execution = await env.ORDER_FLOW.getExecution(executionId);
// { status: "running" | "completed" | "failed", result?: any }

Cancel

Cancel a running execution:

await env.ORDER_FLOW.cancel(executionId);

Step API

step.run

Execute a named step. Results are persisted, so re-runs skip completed steps:

const result = await step.run("step-name", async () => {
	return { data: "value" };
});

step.sleep

Pause execution for a duration (in milliseconds):

await step.sleep(5000); // Wait 5 seconds

Steps that throw are automatically retried. Use unique step names to ensure idempotency.

Next Steps

  • Queues - Send messages for async processing
  • Workers - Learn about Ploy workers

How is this guide?

Last updated on

Workflows