---
title: Durable Objects
description: "Per-id serialized state and alarms, backed by synchronous storage calls."
---

## Configuration

```jsonc
"durable_objects": { "COUNTER": "Counter" }
```

The binding name maps to a class declared in the entry file, above the default export.

## Usage

```js
class Counter {
  constructor(state, env) { this.state = state; this.env = env; }
  // Synchronous, like every other binding: state.storage.* are blocking calls.
  fetch(request) {
    const n = (this.state.storage.get("n") || 0) + 1;
    this.state.storage.put("n", n);
    // Debounced: a burst of requests produces one alarm, not one per request.
    this.state.storage.setAlarm(Date.now() + 1000);
    return Response.json({ n });
  }
  // Runs later, with no request in flight.
  async alarm() {
    await this.env.DB.prepare("INSERT INTO rollup (n) VALUES (?)").bind(this.state.storage.get("n")).run();
  }
}
export default {
  fetch(request) {
    const id = env.COUNTER.idFromName("global");
    return env.COUNTER.get(id).fetch(request);
  },
};
```

## Storage and alarms

`state.storage` has `get`, `put`, `delete`, `deleteAll`, `list({ prefix?, limit? })` (a `Map`), `setAlarm(time)`, `getAlarm()` and `deleteAlarm()`. Each object has at most one pending alarm; a later `setAlarm` replaces it. `state.waitUntil(promise)` works as in a handler.

The namespace has `idFromName(name)`, `idFromString(hex)`, `newUniqueId()` and `get(id)`.

:::note
One sprout process per deployment means calls to a given id are already serialized. Only `state.storage` is persisted, so it survives a restart; fields on the object do not.
:::

## Related

- [D1-compatible SQLite](/docs/bindings/d1): for data shared across objects
