---
description: Reference for every export of agents/lifecycle, including the Lifecycle class, host hooks, capability hooks, Lifecycle services, job types, and context types.
title: Lifecycle API
image: https://developers.cloudflare.com/agents/runtime/lifecycle/api-reference/og.png?v=a9924ce16a6a02ee
---

[Skip to content](#main-content)

> Documentation Index  
> Fetch the complete documentation index at: https://developers.cloudflare.com/agents/llms.txt  
> Use this file to discover all available pages before exploring further.

# Lifecycle API

Last updated Oct 29, 2026|Copy as Markdown| [View as Markdown](https://developers.cloudflare.com/agents/runtime/lifecycle/api-reference/index.md)| [Agent setup](https://developers.cloudflare.com/agent-setup/)

This page lists every export of `agents/lifecycle`. For a guided introduction, refer to [Lifecycle](https://developers.cloudflare.com/agents/runtime/lifecycle/) and [Build a capability](https://developers.cloudflare.com/agents/runtime/capabilities/build-a-capability/).

`agents/lifecycle` is stable.

## Exports

| Export | Kind | Description |
| --- | --- | --- |
| `Lifecycle` | Class | Installs on a Durable Object and runs startup, routing, jobs, and the alarm |
| `LifecycleOptions` | Type | Options for `Lifecycle.install()` and `new Lifecycle()` |
| `LifecycleObject` | Interface | A Durable Object with a `lifecycle` field and host hooks |
| `LifecycleCapability` | Abstract class | Base class for capabilities that use Lifecycle services |
| `DurableObjectCapability` | Interface | The hooks the Lifecycle calls on a capability |
| `LifecycleServices` | Type | Services available to a `LifecycleCapability` as `this.lifecycle` |
| `LifecycleStatus` | Type | `"zero"`, `"starting"`, or `"started"` |
| `LifecycleSockets` | Type | Hibernatable WebSocket access for a capability |
| `LifecycleEvents` | Type | Best-effort event publishing for a capability |
| `LifecycleEvent` | Type | One published event |
| `LifecycleRoutes` | Type | Message routing between Lifecycles |
| `LifecycleRouteAddress` | Type | Address of a routed Lifecycle |
| `LifecycleRouteContext` | Type | Argument of `onRoute()` |
| `LifecycleHostContextScope` | Type | Connection and request passed to `runInHostContext()` |
| `CapabilityStartContext` | Type | Argument of a capability's `onStart()` |
| `CapabilityRequestContext` | Type | Argument of `onRequest()` |
| `CapabilityWebSocketUpgradeContext` | Type | Argument of `onWebSocketUpgrade()` |
| `LifecycleJobs` | Type | Job queue access for the host or one capability |
| `LifecycleJob` | Type | One stored job |
| `LifecycleJobPushOptions` | Type | Options for `jobs.push()` |
| `LifecycleJobContext` | Type | Argument of `onJob()` and `onJobError()` |
| `LifecycleJobOutcome` | Type | Return value of `onJob()` and `onJobError()` |
| `MemoryLimitContext` | Type | Argument of `onMemoryLimit()` and `onAlarmMemoryLimit()` |
| `getCurrentAgent` | Function | Reads the current object, request, and connection |
| `CurrentAgentContext` | Type | Return value of `getCurrentAgent()` |
| `Connection` | Type | A WebSocket connection managed by a capability |
| `ConnectionContext` | Type | Context passed when a connection is accepted |
| `ConnectionState` | Type | Read-only state stored on a connection |
| `ConnectionSetStateFn` | Type | Updater function for `connection.setState()` |
| `WSMessage` | Type | A WebSocket message: `string`, `ArrayBuffer`, or `ArrayBufferView` |

## `Lifecycle`

`Lifecycle<Env, Props>` is generic over the Worker environment and the type of startup props.

### Static methods and constructor

| Member | Description |
| --- | --- |
| `Lifecycle.install(host, options?)` | Constructs a Lifecycle and calls `installHandlers()`. Returns the Lifecycle. |
| `new Lifecycle(host, options?)` | Constructs a Lifecycle without installing handlers. |
| `installHandlers()` | Installs `fetch`, `alarm`, `webSocketMessage`, `webSocketClose`, and `webSocketError` on the host, unless the host already defines them. Throws if called twice. |

### Instance members

| Member | Returns | Description |
| --- | --- | --- |
| `use(capability)` | `this` | Installs a capability. Throws after startup, on a duplicate ID, or on a second catch-all for the same hook. |
| `start(props?)` | `Promise<void>` | Starts capabilities and the host. Called for you on fetch, alarm, and WebSocket events. Call it in RPC methods. |
| `isStarted()` | `boolean` | `true` after every capability and the host `onStart()` have finished. |
| `name` | `string` | The object's name from `ctx.id.name`. Throws when the object has no name. |
| `jobs` | `LifecycleJobs` | The host's view of the [job queue](https://developers.cloudflare.com/agents/runtime/lifecycle/job-queue/). |
| ``sql`...``` | `T[]` | Runs a query against the object's SQLite database with bound parameters. |
| `rearmAlarm()` | `Promise<void>` | Sets the alarm from the job queue. Queue changes call this for you. |
| `trackAlarmWork(promise)` | `boolean` | Keeps work handed off by a job inside the current alarm's memory-limit protection. Returns `false` outside an alarm. |
| `dispose()` | `Promise<void>` | Calls each capability's `dispose()` in reverse registration order. |
| `disableAlarms()` | `Promise<void>` | Deletes the alarm and stops the Lifecycle from setting it again. Use during teardown. |

### `LifecycleOptions`

| Option | Type | Default | Description |
| --- | --- | --- | --- |
| `maxAlarmMemoryLimitStrikes` | `number` | `3` | Consecutive memory-limit resets before the breaker deletes recovery jobs. For more information, refer to [Memory-limit protection](https://developers.cloudflare.com/agents/runtime/lifecycle/job-queue/#memory-limit-protection). |

## `LifecycleObject`

`LifecycleObject<Env, Props>` extends `DurableObject<Env>` with a `lifecycle: Lifecycle<Env, Props>` field and these optional host hooks. Each one runs inside the host context:

| Hook | Returns | When it runs |
| --- | --- | --- |
| `onStart(props?)` | `void \| Promise<void>` | Once per in-memory lifetime, after every capability has started |
| `onRequest(request)` | `Response \| Promise<Response>` | For each HTTP request no capability handled |
| `onAlarm()` | `void \| Promise<void>` | Once per alarm, after due jobs |
| `onJob(context)` | `LifecycleJobOutcome \| void` or a promise | When a host job comes due |
| `onAlarmMemoryLimit(context)` | `void \| Promise<void>` | After an alarm ends in a memory-limit reset, after capability hooks |

`LifecycleObject` is the default type parameter of `getCurrentAgent()`.

## `DurableObjectCapability`

`DurableObjectCapability<Props>` is the interface the Lifecycle calls. Every hook is optional. Hooks run outside the host context.

| Member | Returns | Description |
| --- | --- | --- |
| `claims` | `"selective" \| "catch-all"` | How the capability claims traffic. Defaults to `"selective"`. For more information, refer to [Capability order](https://developers.cloudflare.com/agents/runtime/lifecycle/#request-dispatch). |
| `onStart(context)` | `void` | Creates tables or restores state. Runs in registration order, before the host `onStart()`. `context.props` holds the startup props. |
| `onRequest(context)` | `Response \| undefined` | Handles an HTTP request by returning a `Response`, or passes it on with `undefined`. |
| `onWebSocketUpgrade(context)` | `Response \| undefined` | Claims a WebSocket upgrade by returning a `Response`. The capability then owns the socket for its whole lifetime. |
| `onWebSocketMessage(ws, message)` | `boolean \| void` | Handles a message on a hibernated socket. Return `true` to consume it. |
| `onWebSocketClose(ws, code, reason, wasClean)` | `boolean \| void` | Handles a close on a hibernated socket. Return `true` to consume it. |
| `onWebSocketError(ws, error)` | `boolean \| void` | Handles an error on a hibernated socket. Return `true` to consume it. |
| `onJob(context)` | `LifecycleJobOutcome \| void` | Runs one due job the capability pushed. Keep it short. |
| `onJobError(context, error)` | `LifecycleJobOutcome \| void` | Runs after a job fails its last retry. The return value decides what happens to the job. Returning nothing completes it. |
| `onMemoryLimit(context)` | `void` | Applies policy after an alarm ends in a memory-limit reset. Runs before the host's `onAlarmMemoryLimit()`. Keep writes small. |
| `onRoute(context)` | `unknown` | Handles a message routed to this capability's ID. The return value goes back to the sender. |
| `dispose()` | `void` | Releases live resources during explicit teardown. Does not run on eviction. |

Any hook can also return a promise of its result.

The Lifecycle dispatches each hook as follows:

- `onStart()` runs on every capability, in registration order.
- `onRequest()` and `onWebSocketUpgrade()` are offered in registration order, with the catch-all last. The first `Response` wins.
- `onWebSocketMessage()`, `onWebSocketClose()`, and `onWebSocketError()` are offered in registration order until one returns `true`. Events that no capability consumes are ignored.
- `onJob()` and `onJobError()` go only to the capability that pushed the job.
- `onRoute()` goes only to the capability whose ID the message names.
- `onMemoryLimit()` runs on every capability. A failure in one does not stop the next.
- `dispose()` runs on every capability, in reverse registration order. A failure in one does not stop the next.

### Context types

| Type | Fields |
| --- | --- |
| `CapabilityStartContext<Props>` | `props: Props \| undefined` |
| `CapabilityRequestContext` | `request: Request` |
| `CapabilityWebSocketUpgradeContext` | `request: Request` |
| `LifecycleJobContext` | `job: LifecycleJob`, `attempt: number` |
| `LifecycleRouteContext` | `source: LifecycleRouteAddress \| undefined`, `payload: unknown` |
| `MemoryLimitContext` | `sealed`, `nextTime?`, `executing?`, `purgedRecoveryLoopJobs?`. For more information, refer to [Memory-limit protection](https://developers.cloudflare.com/agents/runtime/lifecycle/job-queue/#memory-limit-protection). |

## `LifecycleCapability`

`LifecycleCapability<Props>` is an abstract class that implements `DurableObjectCapability`. Extend it to receive Lifecycle services.

| Member | Description |
| --- | --- |
| `constructor(id)` | Protected. Takes the capability's stable ID. Throws on an empty ID. |
| `capabilityId` | The ID passed to the constructor. Jobs, events, and routed messages use it. |
| `claims` | `"selective"` by default. Override it with `"catch-all"` when the capability handles all traffic for its hooks. |
| `onStart(context)` | Does nothing by default. Override it to create tables or restore state. |
| `lifecycle` | Protected. The capability's `LifecycleServices`. Throws if the capability is not installed. |
| `lifecycleServices` | Protected. The same services, or `undefined` before installation. |

## `LifecycleServices`

A `LifecycleCapability` reads these services from `this.lifecycle`:

| Member | Type | Description |
| --- | --- | --- |
| `name` | `string` | The object's name. Same as `Lifecycle.name`. |
| `className` | `string` | The host class name, as exported from the Worker. |
| `storage` | `DurableObjectStorage` | The object's storage, including `storage.sql`. |
| `sockets` | `LifecycleSockets` | Accepts and lists hibernatable WebSockets. |
| `ready()` | `() => Promise<void>` | Resolves once startup has finished, starting the object if needed. Rejects if startup fails. Resolves immediately inside startup. |
| `status()` | `() => LifecycleStatus` | `"zero"` before startup, `"starting"` during startup, and `"started"` after. |
| `jobs` | `LifecycleJobs` | The capability's own view of the [job queue](https://developers.cloudflare.com/agents/runtime/lifecycle/job-queue/#manage-jobs). |
| `trackAlarmWork(promise)` | `(work: Promise<unknown>) => boolean` | Keeps work handed off by `onJob()` inside the current alarm's memory-limit protection. Returns `false` outside an alarm. |
| `runInHostContext(fn, scope?)` | `Promise<unknown>` | Runs user code inside the host context, so `getCurrentAgent()` works. `scope` is a `LifecycleHostContextScope`. |
| `events` | `LifecycleEvents` | Publishes best-effort events. |
| `routes` | `LifecycleRoutes` | Sends messages to a capability with the same ID on another Lifecycle. |

### `LifecycleSockets`

| Member | Description |
| --- | --- |
| `accept(ws, tags)` | Accepts a server-side WebSocket for [hibernation](https://developers.cloudflare.com/durable-objects/best-practices/websockets/) with the given tags. |
| `get(tag?)` | Returns every hibernated WebSocket on the object, optionally filtered by tag. |

These are the Durable Object's `ctx.acceptWebSocket()` and `ctx.getWebSockets()`. `get()` returns sockets that other capabilities own too, so filter by your own tag.

### `LifecycleHostContextScope`

| Field | Type | Description |
| --- | --- | --- |
| `connection` | `Connection \| undefined` | The connection the user code runs on behalf of |
| `request` | `Request \| undefined` | The request the user code runs on behalf of |

### `LifecycleEvents` and `LifecycleEvent`

`events.emit(type, payload)` publishes a `LifecycleEvent` with these fields:

| Field | Type | Description |
| --- | --- | --- |
| `source` | `string` | The capability ID, or `"lifecycle"` for queue events |
| `type` | `string` | Event name, such as `uptime:check` |
| `payload` | `unknown` | Event data |

Both `source` and `type` must be non-empty. Events emitted before startup finishes are held until it does. On a plain Durable Object, the Lifecycle publishes each event to an `agents:*` [diagnostics channel](https://developers.cloudflare.com/agents/runtime/observability/diagnostics-channels/) chosen by the prefix of `type`. Unknown prefixes go to `agents:lifecycle`. The published message adds the host class name as `agent`, the object `name`, and a `timestamp`.

### `LifecycleRoutes`

| Member | Description |
| --- | --- |
| `source` | This Lifecycle's `LifecycleRouteAddress`, or `undefined` on a root object. |
| `toRoot(payload)` | Sends `payload` to the capability with the same ID on the root Lifecycle, and resolves to its `onRoute()` result. |
| `to(target, payload)` | Sends `payload` to the capability with the same ID on the Lifecycle at `target`. |

A `LifecycleRouteAddress` has a `key`, used for equality and storage, and a serialized `data` string.

Routing between Lifecycles needs a transport that the host provides. The `Agent` class provides one for its sub-agents. On a plain Durable Object there is no transport: `source` is `undefined`, `toRoot()` delivers to the capability's own `onRoute()` on the same object, and `to()` throws.

## Own WebSocket connections

A capability that accepts its own WebSockets claims the upgrade, accepts the socket through `sockets.accept()`, and marks it with a hibernation attachment. After a wake, the Lifecycle offers each socket event to every capability in order, so each capability must recognize its own sockets and return `true` only for those:

```js
import { LifecycleCapability } from "agents/lifecycle";

const TAG = "echo";

export class EchoSockets extends LifecycleCapability {
	constructor() {
		super("echo-sockets");
	}

	onWebSocketUpgrade({ request }) {
		if (!new URL(request.url).pathname.endsWith("/echo")) return;
		const { 0: client, 1: server } = new WebSocketPair();
		server.serializeAttachment({ owner: TAG });
		this.lifecycle.sockets.accept(server, [TAG]);
		return new Response(null, { status: 101, webSocket: client });
	}

	onWebSocketMessage(ws, message) {
		if (!this.#owns(ws)) return false;
		ws.send(message);
		return true;
	}

	onWebSocketClose(ws, code, reason) {
		if (!this.#owns(ws)) return false;
		ws.close(code, reason);
		return true;
	}

	get connectionCount() {
		return this.lifecycle.sockets.get(TAG).length;
	}

	#owns(ws) {
		const attachment = ws.deserializeAttachment();
		return attachment?.owner === TAG;
	}
}
```

```ts
import {
	LifecycleCapability,
	type CapabilityWebSocketUpgradeContext,
	type WSMessage,
} from "agents/lifecycle";

const TAG = "echo";

export class EchoSockets extends LifecycleCapability {
	constructor() {
		super("echo-sockets");
	}

	onWebSocketUpgrade({
		request,
	}: CapabilityWebSocketUpgradeContext): Response | undefined {
		if (!new URL(request.url).pathname.endsWith("/echo")) return;
		const { 0: client, 1: server } = new WebSocketPair();
		server.serializeAttachment({ owner: TAG });
		this.lifecycle.sockets.accept(server, [TAG]);
		return new Response(null, { status: 101, webSocket: client });
	}

	onWebSocketMessage(ws: WebSocket, message: WSMessage): boolean {
		if (!this.#owns(ws)) return false;
		ws.send(message);
		return true;
	}

	onWebSocketClose(ws: WebSocket, code: number, reason: string): boolean {
		if (!this.#owns(ws)) return false;
		ws.close(code, reason);
		return true;
	}

	get connectionCount(): number {
		return this.lifecycle.sockets.get(TAG).length;
	}

	#owns(ws: WebSocket): boolean {
		const attachment = ws.deserializeAttachment() as { owner?: string } | null;
		return attachment?.owner === TAG;
	}
}
```

`EchoSockets` can sit beside the `WebSockets` capability. `WebSockets` is a catch-all for upgrades, so the Lifecycle offers each upgrade to `EchoSockets` first, whatever the install order. For most real-time clients, use the [`WebSockets` capability](https://developers.cloudflare.com/agents/runtime/capabilities/websockets/) instead.

## Job types

The job types are described on [Jobs and alarms](https://developers.cloudflare.com/agents/runtime/lifecycle/job-queue/):

- `LifecycleJobs`: refer to [Manage jobs](https://developers.cloudflare.com/agents/runtime/lifecycle/job-queue/#manage-jobs).
- `LifecycleJobPushOptions`: refer to [Push options](https://developers.cloudflare.com/agents/runtime/lifecycle/job-queue/#push-options).
- `LifecycleJob`: refer to [The `LifecycleJob` shape](https://developers.cloudflare.com/agents/runtime/lifecycle/job-queue/#the-lifecyclejob-shape).
- `LifecycleJobOutcome`: refer to [Control what happens after a job runs](https://developers.cloudflare.com/agents/runtime/lifecycle/job-queue/#control-what-happens-after-a-job-runs).
- `MemoryLimitContext`: refer to [Memory-limit protection](https://developers.cloudflare.com/agents/runtime/lifecycle/job-queue/#memory-limit-protection).

## Connection types

`agents/lifecycle` defines the connection types, so that both the `WebSockets` capability and `getCurrentAgent()` can use them:

| Type | Description |
| --- | --- |
| `Connection<TState>` | A `WebSocket` with `id`, `uri` (the upgrade URL), read-only `state`, `setState()`, and `tags`. The first tag is always the connection ID. |
| `ConnectionContext` | `{ request: Request }`, the original upgrade request. |
| `ConnectionState<T>` | Immutable connection state, or `null`. Stored in the socket's hibernation attachment. |
| `ConnectionSetStateFn<T>` | `(prevState: ConnectionState<T>) => T`, an updater for `connection.setState()`. |
| `WSMessage` | `string \| ArrayBuffer \| ArrayBufferView`. |

For how connections work, refer to [WebSockets](https://developers.cloudflare.com/agents/runtime/capabilities/websockets/).

## `getCurrentAgent()` types

`getCurrentAgent<Host>()` returns a `CurrentAgentContext<Host>` with `agent`, `connection`, `request`, and `email`. For more information, refer to [`getCurrentAgent()`](https://developers.cloudflare.com/agents/runtime/lifecycle/get-current-agent/).

Was this helpful?

YesNo

## On this page

[![](https://developers.cloudflare.com/_astro/logo.te5VL_aD.svg)Docs](https://developers.cloudflare.com/)

```json
{"@context":"https://schema.org","@type":"TechArticle","@id":"https://developers.cloudflare.com/agents/runtime/lifecycle/api-reference/#page","headline":"Lifecycle API","description":"Reference for every export of agents/lifecycle, including the Lifecycle class, host hooks, capability hooks, Lifecycle services, job types, and context types.","url":"https://developers.cloudflare.com/agents/runtime/lifecycle/api-reference/","inLanguage":"en","image":"https://developers.cloudflare.com/agents/runtime/lifecycle/api-reference/og.png?v=a9924ce16a6a02ee","dateModified":"2026-10-29","publisher":{"@type":"Organization","name":"Cloudflare","description":"One platform for your apps, agents, and workforce. Build, secure, and scale without managing infrastructure","url":"https://www.cloudflare.com/","sameAs":["https://github.com/cloudflare","https://www.linkedin.com/company/cloudflare","https://x.com/cloudflare"],"logo":{"@type":"ImageObject","url":"https://developers.cloudflare.com/logo.svg"},"address":{"@type":"PostalAddress","streetAddress":"101 Townsend St","addressLocality":"San Francisco","addressRegion":"CA","postalCode":"94107","addressCountry":"US"},"contactPoint":[{"@type":"ContactPoint","contactType":"Customer Support","url":"https://support.cloudflare.com/","availableLanguage":["English"]},{"@type":"ContactPoint","contactType":"Sales","url":"https://www.cloudflare.com/contact/","availableLanguage":["English"]}]},"isPartOf":{"@type":"WebSite","@id":"https://developers.cloudflare.com/#website","name":"Cloudflare Docs","url":"https://developers.cloudflare.com/"}}
```
