setAttributes

Attaches string metadata to the current workflow run.

import { setAttributes } from "workflow"

export async function orderWorkflow(orderId: string) {
  "use workflow"

  await setAttributes({
    phase: "received",
    orderId,
  })
}

API signature

Parameters

NameTypeDescription
attrsRecord<string, string | undefined>
optionsSetAttributesOptions

Usage

Call setAttributes from a "use workflow" function or a "use step" function. Calling it from plain application code is not supported because there is no active workflow run.

Attribute values must be strings. Pass undefined to remove an attribute:

import { setAttributes } from "workflow"

export async function cleanupAttributes() {
  "use workflow"

  await setAttributes({ staleKey: undefined })
}

Attribute keys must be 1-256 characters, values must be strings up to 256 bytes, and each run can have up to 64 attributes. Keys that start with $ are reserved for framework and library code.

Each call's complete attr_set event data must also fit in 8192 UTF-8 JSON bytes (8KiB). This includes the change keys and values, JSON escaping and structure, writer metadata (including the step ID and attempt for step calls), and the reserved-key option when enabled. It is not a limit on values alone. Split large updates into smaller calls; updates across multiple calls are not atomic and still share the 64-attribute per-run limit.

Validation errors reject setAttributes with FatalError before a new attribute write is attempted. Catch the error if the metadata is best-effort; an uncaught error fails the workflow or step. Previously persisted attribute events remain replayable.

Calls from both workflow and step bodies append a native attr_set event, which the World materializes onto run.attributes. Workflow-originated events record a workflow writer; step-originated events record the originating step ID and attempt.

Native attributes require spec version 4 or later. Step-body storage errors throw from setAttributes; catch them inside the step if the write should be best-effort. Workflow-body writes are committed when the workflow suspends: transient storage errors are retried with the suspension, while a write the World rejects as invalid (such as exceeding the per-run attribute cap across multiple calls) fails the run with the validation error.