Quickstart
Install and configure the Workflows fragment.
Overview
The Workflows fragment provides durable, replayable workflow execution with steps, timers, retries, and external events. This quickstart walks through defining a workflow, wiring durable hooks, and exposing routes.
Installation
Install the fragment and database packages:
npm install @fragno-dev/workflows @fragno-dev/dbDefine a Workflow
Create a workflow definition and a registry of workflows:
import { defineWorkflow, type WorkflowEvent, type WorkflowStep } from "@fragno-dev/workflows";
type ApprovalParams = {
requestId: string;
amount: number;
};
type ApprovalEvent = { approved: boolean };
type FulfillmentEvent = { confirmationId: string };
export const ApprovalWorkflow = defineWorkflow(
{ name: "approval-workflow" },
async (event: WorkflowEvent<ApprovalParams>, step: WorkflowStep) => {
const approval = await step.waitForEvent<ApprovalEvent>("approval", {
type: "approval",
timeout: "15 min",
});
await step.sleep("cooldown", "2 s");
const fulfillment = await step.waitForEvent<FulfillmentEvent>("fulfillment", {
type: "fulfillment",
timeout: "15 min",
});
return { request: event.payload, approval, fulfillment };
},
);
export const workflows = {
approval: ApprovalWorkflow,
} as const;Optional: pass a Standard Schema as schema to validate params, and an outputSchema to type
output end-to-end.
import { z } from "zod";
const paramsSchema = z.object({ requestId: z.string(), amount: z.number() });
const outputSchema = z.object({ confirmationId: z.string() });
export const ApprovalWorkflow = defineWorkflow(
{ name: "approval-workflow", schema: paramsSchema, outputSchema },
async (event, step) => ({ confirmationId: "conf_123" }),
);Create the Fragment Server
Wire the durable hooks dispatcher and fragment definition:
import { defaultFragnoRuntime, instantiate } from "@fragno-dev/core";
import { type DatabaseAdapter } from "@fragno-dev/db";
import { createDurableHooksProcessor } from "@fragno-dev/db/dispatchers/node";
import { workflowsFragmentDefinition, workflowsRoutesFactory } from "@fragno-dev/workflows";
import { workflows } from "./workflows";
export function createWorkflowsFragmentServer(adapter: DatabaseAdapter<any>) {
const runtime = defaultFragnoRuntime;
const config = { workflows, runtime };
const fragment = instantiate(workflowsFragmentDefinition)
.withConfig(config)
.withRoutes([workflowsRoutesFactory])
.withOptions({ databaseAdapter: adapter })
.build();
const dispatcher = createDurableHooksProcessor([fragment], {
pollIntervalMs: 2000,
});
dispatcher.startPolling();
process.on("SIGTERM", () => dispatcher.stopPolling());
return { fragment, dispatcher };
}The in-process dispatcher is ideal for local dev. For Cloudflare deployments use
@fragno-dev/db/dispatchers/cloudflare-do.
Mount the Routes
Mount the fragment using your framework adapter. See Integrating a Fragment for framework-specific examples.
Run Database Migrations
Generate a schema and run migrations with the Fragno CLI:
npx fragno-cli db generate lib/workflows-fragment.ts --format drizzle -o db/workflows.schema.ts
npx fragno-cli db migrate lib/workflows-fragment.tsTest Workflows
Use the test harness to drive workflow ticks with a controllable clock and deterministic runtime:
import { createWorkflowsTestHarness, createWorkflowsTestRuntime } from "@fragno-dev/workflows/test";
import { workflows } from "./workflows";
const runtime = createWorkflowsTestRuntime({ startAt: 0, seed: 123 });
const harness = await createWorkflowsTestHarness({
workflows,
adapter: { type: "drizzle-pglite" },
runtime,
});
const instanceId = await harness.createInstance("approval", {
params: { requestId: "req_1", amount: 125 },
});
await harness.runUntilIdle();
await harness.sendEvent("approval", instanceId, {
type: "approval",
payload: { approved: true },
});
harness.clock.advanceBy("2 s");
await harness.runUntilIdle();For higher-level scripting, see the Scenario DSL guide.
Drive the Runner
For external schedulers, run a durable hooks dispatcher (Node or Cloudflare DO) so hooks are processed when work is enqueued.
Use the CLI
The fragno-wf CLI uses the HTTP API to list workflows, inspect instances, and send events:
fragno-wf workflows list -b https://your-app.example.com/api/workflows
fragno-wf instances get -b https://your-app.example.com/api/workflows -w approval -i inst_123Next Steps
- Build a client or CLI on top of the HTTP API in the fragment.
- Review workflow history and logs using the
/historyroutes.