Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/eersnington/sideffect/llms.txt

Use this file to discover all available pages before exploring further.

Every Step.make run function receives a second argument — a StepContext — that provides everything the step needs to interact with its environment and introspect its own execution. StepContext extends Cloudflare’s native WorkflowStepContext, so the fields you already know from vanilla Cloudflare Workflows are all present, augmented by Sideffect’s typed env and workflowStep properties.

The StepContext Interface

interface StepContext<Env = DefaultCloudflareEnv> extends WorkflowStepContext {
  readonly env:          Env;
  readonly ctx:          unknown;
  readonly workflowStep: NativeWorkflowStep;
  // inherited from WorkflowStepContext:
  readonly attempt:      number;
  readonly step: {
    readonly name: string;
  };
  readonly config:       WorkflowStepConfig;
}

ctx.env — Worker Bindings

ctx.env is typed from the global Cloudflare.Env interface, giving you full TypeScript autocompletion for every binding in your Worker — R2 buckets, KV namespaces, AI, Durable Objects, Queues, and more.
const fetchImageStep = Step.make("fetch image", {
  payload: Schema.Struct({ imageKey: Schema.String }),
  result: Schema.Struct({ data: Schema.Uint8Array }),
  run: async ({ imageKey }, ctx) => {
    const object = await ctx.env.BUCKET.get(imageKey);
    const data = new Uint8Array(await object!.arrayBuffer());
    return { data };
  },
});
ctx.env typing comes from the global Cloudflare.Env interface, which is generated by running wrangler types in your project. If you use Sideffect’s Vite adapter, it also emits a sideffect-env.d.ts file that augments Cloudflare.Env with the workflow binding types it generates. You never need to write these type declarations by hand.

ctx.attempt — Retry Attempt Count

ctx.attempt is a 1-based integer that tells you how many times Cloudflare has tried to execute this step in the current workflow run. On the first execution it is 1; on the first retry it is 2, and so on. This is useful for logging, skipping expensive setup on retries, or making decisions about fallback behaviour.
const describeImageStep = Step.make("describe image", {
  payload: Schema.Struct({ imageData: Schema.Uint8Array }),
  result: Schema.Struct({ description: Schema.String }),
  run: async ({ imageData }, ctx) => {
    if (ctx.attempt > 1) {
      console.warn(`Retrying ${ctx.step.name}, attempt ${ctx.attempt}`);
    }

    const result = await ctx.env.AI.run("@cf/llava-hf/llava-1.5-7b-hf", {
      image: Array.from(imageData),
      prompt: "Describe this image in one sentence",
      max_tokens: 50,
    });

    return { description: result.description };
  },
});

ctx.step.name — Step Name

ctx.step.name is the human-readable name you passed as the first argument to Step.make. It matches the name Cloudflare records in its Workflow execution history.

ctx.config — Resolved Step Configuration

ctx.config is the resolved WorkflowStepConfig for the current step invocation. It includes the timeout, retries, and sensitive values that were passed to step.do() in the workflow (or Cloudflare’s defaults if none were provided).

ctx.workflowStep — Native Step API

ctx.workflowStep exposes the underlying NativeWorkflowStep object for cases where you need direct access to Cloudflare’s step primitives from within a step’s run function. In most cases you will not need this — use the SideffectStep façade in your workflow’s run function instead.

Workbench Example — readStepContext

The following step (from the Sideffect workbench) reads all three context properties and returns them as part of its result, demonstrating how each field is accessed:
export const readStepContext = Step.make("read step context", {
  payload: Schema.Struct({ label: Schema.String }),
  result: Schema.Struct({
    label:   Schema.String,
    step:    Schema.String,
    attempt: Schema.Number,
    timeout: Schema.String,
  }),
  run: ({ label }, ctx) => ({
    label,
    step:    ctx.step.name,
    attempt: ctx.attempt,
    timeout: String(ctx.config.timeout),
  }),
});
The workflow that calls it passes a custom timeout via step.do options:
export const stepContextLayer = Workflow.make({
  name: "step-context",
  payload: Schema.Struct({ label: Schema.String }),
}).toLayer(async ({ payload }, step) => {
  return step.do(readStepContext, payload, { timeout: "5 minutes" });
});
Inside readStepContext, ctx.config.timeout will reflect the "5 minutes" value that was passed through.

StepContext Property Reference

PropertyTypeDescription
ctx.envEnvTyped Worker environment bindings (R2, KV, AI, Durable Objects, etc.).
ctx.ctxunknownWorker execution context from the WorkflowEntrypoint instance.
ctx.attemptnumberCurrent retry attempt, 1-based. 1 on first execution, 2 on first retry.
ctx.step.namestringThe name string passed to Step.make.
ctx.configWorkflowStepConfigResolved step configuration (timeout, retries, sensitive).
ctx.workflowStepNativeWorkflowStepRaw Cloudflare WorkflowStep API for advanced native operations.

Steps

Define reusable, schema-validated workflow activities.

Workflows

Compose steps into full workflow pipelines.

Rollback

Attach compensation handlers to steps with Rollback.with().

Error Handling

Throw NonRetryableError to stop retries immediately.

Build docs developers (and LLMs) love