# Functional Difference Between Resident and Hibernated Cells in celld: A Complete Guide

> Understand the functional difference between resident and hibernated cells in celld. Discover how resident cells ensure fast responses while hibernated cells optimize memory usage by persisting to disk.

- Repository: [Deno/celld](https://github.com/denoland/celld)
- Tags: deep-dive
- Published: 2026-08-09

---

**Resident cells remain loaded in memory with active SQLite connections for instant request handling, while hibernated cells are persisted to disk as snapshots to free RAM, requiring re-activation overhead when accessed.**

The `denoland/celld` runtime manages Durable Object (DO) state through an abstraction called **cells**, each existing in specific lifecycle phases that determine storage location and access speed. Understanding the **functional difference between resident cells and hibernated cells in celld** is essential for optimizing performance and resource allocation in production deployments. These two states represent the fundamental trade-off between memory consumption and request latency within the system's state machine.

## Lifecycle Phases and State Machine

The celld architecture defines cell states through the `Phase` enum, distinguishing between active memory-resident instances and disk-persisted hibernated snapshots.

### The Resident Phase

A cell enters the **resident** phase when it occupies active memory with an open database connection. In [`crates/logic/lib.rs`](https://github.com/denoland/celld/blob/main/crates/logic/lib.rs), the `Phase::Resident { epoch }` variant (lines 814‑816) marks cells that are kept **in-memory** with an open SQLite connection, allowing the executor to run top-level Worker requests directly on the loaded isolate without disk I/O. This state provides the fastest possible request handling because the isolate, its SQLite WAL, and file handles are already initialized and ready.

### The Hibernated Phase

When a cell is **hibernated**, it is evicted from memory and its state is serialized to disk. The SQLite database connection is closed, and a snapshot is written to a `.hibernated` file, leaving the cell dormant until explicitly reactivated. According to the connection management logic in [`crates/celld/storage.rs`](https://github.com/denoland/celld/blob/main/crates/celld/storage.rs) (lines 9‑12), the system follows an "`open` on activate, `close` on hibernate" policy, ensuring that hibernated cells consume no RAM while maintaining durability through disk snapshots.

## Performance and Resource Characteristics

The choice between keeping a cell resident or allowing it to hibernate directly impacts node performance and capacity planning.

### Latency and Throughput

**Resident cells** deliver very low latency because requests execute immediately against the loaded isolate. In contrast, accessing a **hibernated cell** incurs significant overhead: the runtime must first restore the `.hibernated` snapshot, reopen the SQLite database, and reconstruct the isolate environment before processing the request.

### Memory Constraints and Limits

Resident cells consume RAM for the isolate heap, SQLite WAL, and file descriptors, bounded by the `CELLD_MAX_RESIDENT_CELLS` hard cap. Hibernated cells free these resources, allowing a node to host substantially more cells than physical memory permits, limited instead by the `CELLD_HIBERNATIONS` configuration. This architecture enables celld to support large fleets of rarely-accessed Durable Objects without exhausting memory.

## State Transitions and Activation Mechanics

Cells transition between resident and hibernated states based on request patterns and resource pressure.

### Becoming Resident

Cells become resident when a top-level Worker fetch targets their ID and a resident slot is available under the `CELLD_MAX_RESIDENT_CELLS` limit. The scheduler pins the isolate for the request duration, ensuring subsequent operations on that cell remain fast.

### The Hibernation Process

When eviction logic determines that memory pressure requires freeing resources, the runtime invokes the async `hibernate` method defined in [`crates/celld/runtime.rs`](https://github.com/denoland/celld/blob/main/crates/celld/runtime.rs) (lines 216‑225). This method delegates to `ltx_repl::hibernate` to serialize the cell state to a `.hibernated` snapshot while [`storage.rs`](https://github.com/denoland/celld/blob/main/storage.rs) closes the underlying database connection. The [`logic/lib.rs`](https://github.com/denoland/celld/blob/main/logic/lib.rs) module tracks which cells are eligible for hibernation through the `hibernation_permits` field (lines 82‑84), recording timestamps when hibernation requests are refused due to active locks.

### Reactivation from Hibernation

When a request arrives for a hibernated cell, the runtime executes an activation sequence: it locates the existing `.hibernated` snapshot, restores the database state, reopens the SQLite connection via the storage layer, and transitions the cell back to `Phase::Resident`. This process is significantly slower than resident access but ensures that infrequently used cells do not consume active resources.

## Implementation Details in Source Code

The distinction between resident and hibernated cells is enforced across several core modules:

- **[`crates/logic/lib.rs`](https://github.com/denoland/celld/blob/main/crates/logic/lib.rs)**: Defines the `Phase` enum including `Phase::Resident { epoch }` and manages hibernation permits that control eviction eligibility.
- **[`crates/celld/storage.rs`](https://github.com/denoland/celld/blob/main/crates/celld/storage.rs)**: Maintains the map of open connections and implements the lifecycle policy documented at lines 9‑12, explicitly closing databases on hibernate.
- **[`crates/celld/runtime.rs`](https://github.com/denoland/celld/blob/main/crates/celld/runtime.rs)**: Implements the `hibernate` and `activate` async methods that orchestrate state transitions and snapshot management.
- **[`crates/celld/ltx_repl.rs`](https://github.com/denoland/celld/blob/main/crates/celld/ltx_repl.rs)**: Handles the creation, compression, and reuse of `.hibernated` snapshot files on disk.

## Practical Code Examples

The following Rust patterns demonstrate interacting with both cell states:

```rust
// Fast-path execution against a resident cell
let cell_id = "my-do";
let epoch = state.cells[&cell_id].phase; // → Phase::Resident { epoch }
runtime.dispatch_do_call(cell_id, request).await?; // No DB reload required

```

```rust
// Explicitly hibernating a cell to free memory
await runtime.hibernate(cell_id, epoch, preserve_local = true).await?;
state.cells.get_mut(cell_id).unwrap().phase = Phase::Remote { /* … */ };

```

```rust
// Reactivating a hibernated cell (higher latency)
let result = runtime.activate(cell_id, epoch).await?;
match result {
    Phase::Resident { .. } => println!("Cell is now resident again!"),
    _ => panic!("Unexpected phase"),
}

```

## Summary

- **Resident cells** maintain active SQLite connections and isolates in RAM, providing immediate request execution but consuming memory limited by `CELLD_MAX_RESIDENT_CELLS`.
- **Hibernated cells** are persisted as `.hibernated` snapshots on disk with closed database connections, freeing RAM but requiring snapshot restoration and DB reopening on access.
- State transitions are managed through `runtime.hibernate()` and `runtime.activate()` in [`crates/celld/runtime.rs`](https://github.com/denoland/celld/blob/main/crates/celld/runtime.rs), with connection lifecycle handled by [`storage.rs`](https://github.com/denoland/celld/blob/main/storage.rs).
- The system uses `hibernation_permits` in [`crates/logic/lib.rs`](https://github.com/denoland/celld/blob/main/crates/logic/lib.rs) to coordinate safe eviction under memory pressure.

## Frequently Asked Questions

### When does celld decide to hibernate a cell?

The eviction logic triggers hibernation when the node experiences memory pressure and the number of resident cells approaches the `CELLD_MAX_RESIDENT_CELLS` hard cap. Cells that have been inactive and hold valid `hibernation_permits` (tracked in [`crates/logic/lib.rs`](https://github.com/denoland/celld/blob/main/crates/logic/lib.rs)) are selected for hibernation to free resources for active workloads.

### How does hibernation affect request latency?

Accessing a resident cell incurs minimal latency because the isolate and database are already loaded. A hibernated cell requires restoring the `.hibernated` snapshot from disk and reopening the SQLite connection, introducing significant latency overhead compared to the resident fast path.

### What limits the number of hibernated cells?

While hibernated cells consume minimal RAM, their quantity is bounded by the `CELLD_HIBERNATIONS` configuration parameter and available disk storage for `.hibernated` snapshot files. Unlike resident cells, hibernated instances do not hold open file descriptors or database connections.

### Can data be lost when a cell hibernates?

No. The hibernation process in [`crates/celld/runtime.rs`](https://github.com/denoland/celld/blob/main/crates/celld/runtime.rs) ensures durability by writing a complete snapshot to the `.hibernated` file before closing the database connection. The [`storage.rs`](https://github.com/denoland/celld/blob/main/storage.rs) module guarantees that all WAL entries are flushed during the "`close` on hibernate" operation, making hibernation a safe, crash-resistant state.