---
title: "Durability"
description: "Volatile vs durable mode, the pre-ready buffer, and when fire() is not enough."
---

> Documentation Index
> Fetch the complete documentation index at: https://logbun-docs.abshahin.workers.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Durability

`LogbunConfig.mode` is `'volatile'` (default) or `'durable'`.

## Volatile

The root constructs an internal `MemoryReliabilityAdapter` when `reliability` is omitted. `persistent` is always `false`. Unflushed queues, the optional in-process journal, and the memory DLQ are lost on process exit.

Volatile mode emits `limit` / `unsafe_default_volatile` once at construction (including when you set `mode: 'volatile'` explicitly).

On request-scoped hosts (Workers, serverless), detached `fire()` is not a delivery guarantee. Use:

```ts
await audit.fireAsync('user.created', { actorId: 'u1' });
await audit.flush();
```

## Durable

Durable mode **requires** a reliability adapter with `persistent: true`. Missing reliability or `MemoryReliabilityAdapter` throws **synchronously** in the constructor:

```text
durable mode requires LogbunConfig.reliability with a persistent adapter
  (e.g. FileReliabilityAdapter from "logbun/durability/filesystem" or
  CloudflareReliabilityAdapter from "logbun/durability/cloudflare")
```

```text
durable mode requires a persistent ReliabilityAdapter
  (MemoryReliabilityAdapter is not durable)
```

`ENTERPRISE_DEFAULTS` is only `{ mode: 'durable', requireTenantId: true }`. Spreading it without a persistent `reliability` still throws.

Persistent backends:

| Adapter | Import | Survives |
|---------|--------|----------|
| `FileReliabilityAdapter` | `logbun/durability/filesystem` | Process death, if the disk is intact |
| `CloudflareReliabilityAdapter` | `logbun/durability/cloudflare` | Isolate exit, inside a SQLite Durable Object |

## Pre-ready buffer

`audit.ready` is a bootstrap promise. **It never rejects.** Failure sets `degraded` and emits `bootstrap_fail` / `degraded`.

Logs accepted before `ready` sit in a **volatile** buffer (`maxPreReadyBuffer`, default 10_000) even when `mode: 'durable'`. Excess emits `drop` / `pre_ready_buffer_full`. Durable-mode pre-ready accepts also emit `limit` / `pre_ready_volatile`.

Await `ready` before `fire` / `fireAsync` in durable mode. Bootstrap drains the buffer through the real enqueue path (including journal) before `ready` resolves.

## `fire` vs `fireAsync`

| | `fire()` | `fireAsync()` |
|--|----------|---------------|
| Throws | never | yes |
| Returns | `void` | `Promise<void>` |
| Durable admission | background; pass `waitUntil` on Workers | awaited |
| Missing tenant when required | `drop` / `require_tenant_id` | rejects |
| Oversize `tenantId` | `drop` / `max_tenant_id_bytes` | rejects |
| Degraded | `drop` / `degraded` | rejects `AuditLogger is degraded — fireAsync unavailable` |

If a Cloudflare journal/DLQ row commits but `getAlarm` / `setAlarm` fails, `fireAsync` rejects with `DurableAdmissionSchedulingError` and `durableAdmissionCommitted === true`. Do **not** resubmit that event; call `requestMaintenance()` after the scheduler recovers. `fire()` rethrows that error *into* the `waitUntil` task (and emits `flush_fail` / `durable_admission_scheduling`) so Workers keep the isolate awake; `fire()` itself still does not throw.

```ts
import { isDurableAdmissionSchedulingError } from 'logbun';

try {
  await audit.fireAsync('audit.event', input);
} catch (error) {
  if (isDurableAdmissionSchedulingError(error)) {
await reliability.requestMaintenance();
  } else {
throw error;
  }
}
```

`isDurableAdmissionSchedulingError` accepts the class instance **or** a duck type with `name === 'DurableAdmissionSchedulingError'` **and** `durableAdmissionCommitted === true`. A lone `{ durableAdmissionCommitted: true }` is not this error.

## Degraded

After bootstrap failure, `audit.degraded` is `true`. `fire` drops; `fireAsync`, `query`, DLQ ops, `flush`, and maintenance throw `AuditLogger is not initialized` (or the fireAsync degraded message). Open a new logger to recover.

Source: https://logbun-docs.abshahin.workers.dev/concepts/durability/index.mdx
