#[workflow]Expand description
Marks a function as a durable workflow.
Workflows are multi-step processes that survive restarts and handle failures with compensation. Each workflow has a stable logical name, an explicit user-facing version, and a derived signature that acts as the hard runtime safety gate for resumption.
§Versioning
When you make a breaking change to a workflow’s persisted contract (add/remove steps, rename wait keys, change event contracts), create a new version. Keep the old version in the binary until its incomplete runs drain.
The runtime derives a signature from step keys, wait keys, timeout, and type shapes. If you change the persisted contract under the same version, registration will fail.
§Authentication
By default, workflows require an authenticated user to start. Override with:
public- Can be started without authenticationrequire_role("admin")- Requires specific role to start
§Attributes
name = "logical_name"- Stable workflow name (defaults to function name)version = "2026-05"- User-facing version id (dates, semver, or labels)active- This is the active version; new runs start here (default if neither set)deprecated- Kept for draining old runs; no new runs will start on this versiontimeout = "24h"- Maximum execution time. Also becomes the default outbound HTTP timeout forctx.http()when explicitly set
§Example
// Old version kept alive for draining incomplete runs
#[forge::workflow(name = "user_onboarding", version = "2026-03", deprecated)]
pub async fn user_onboarding_v1(ctx: &WorkflowContext, input: Input) -> Result<Output> {
let user = ctx.step("create_user", || async { /* ... */ }).await?;
ctx.step("send_welcome", || async { /* ... */ }).await;
Ok(Output { user })
}
// New active version with an additional step
#[forge::workflow(name = "user_onboarding", version = "2026-05", active)]
pub async fn user_onboarding_v2(ctx: &WorkflowContext, input: Input) -> Result<Output> {
let user = ctx.step("create_user", || async { /* ... */ }).await?;
ctx.step("send_welcome", || async { /* ... */ }).await;
ctx.step("sync_crm", || async { /* ... */ }).await;
Ok(Output { user })
}