Skip to main content
Workflow.sleep() pauses a workflow for a specified duration. Unlike Effect.sleep, the pause is fully durable — if your server restarts or a new deployment happens while the workflow is sleeping, it resumes automatically when the scheduled time arrives.
yield* Workflow.sleep("24 hours");  // Pause for a full day

Duration formats

Both string and millisecond formats are accepted. String format:
yield* Workflow.sleep("30 seconds");
yield* Workflow.sleep("5 minutes");
yield* Workflow.sleep("24 hours");
yield* Workflow.sleep("30 days");
Milliseconds:
yield* Workflow.sleep(5000);   // 5 seconds
yield* Workflow.sleep(30000);  // 30 seconds

Workflow.sleepUntil()

To sleep until a specific point in time, pass a Unix timestamp in milliseconds:
const renewalDate = getSubscriptionRenewalDate(); // number (ms timestamp)
yield* Workflow.sleepUntil(renewalDate);
If the timestamp is already in the past, sleepUntil returns immediately without pausing.

Common patterns

const subscriptionWorkflow = Workflow.make((userId: string) =>
  Effect.gen(function* () {
    yield* Workflow.step({
      name: "Activate subscription",
      execute: activateSubscription(userId),
    });

    // Wait 30 days before checking for renewal
    yield* Workflow.sleep("30 days");

    yield* Workflow.step({
      name: "Send renewal reminder",
      execute: sendRenewalEmail(userId),
    });
  })
);
// Rate limiting between API calls
yield* Workflow.step({ name: "First request", execute: callAPI(page1) });
yield* Workflow.sleep("30 seconds");
yield* Workflow.step({ name: "Second request", execute: callAPI(page2) });

How sleep works internally

When Workflow.sleep() is called for the first time at a given pause point, it:
  1. Records the resumeAt timestamp in Durable Object storage
  2. Throws a PauseSignal with reason: "sleep" — this is caught by the executor, not propagated as an error
  3. The orchestrator transitions the workflow to Paused and schedules a Cloudflare Durable Object alarm for resumeAt
When the alarm fires, the orchestrator transitions the workflow back to Running and re-executes it in resume mode. On replay, all previously completed steps return their cached results, and the sleep point is skipped because its pause index has already been recorded as completed.
Sleeps are tracked by index, not by duration. If you add or reorder sleep calls between a workflow being paused and resumed, behavior may be undefined. Treat the sequence of Workflow.sleep() calls in a workflow as immutable once instances are running.

Build docs developers (and LLMs) love