# Celld Local Cache Mechanism for Hibernated Cells: How On-Disk Snapshots Enable Fast Rehydration

> Explore Celld's local cache mechanism for hibernated cells. Learn how on-disk snapshots enable fast rehydration by saving cell state without re-executing constructors.

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

---

**Celld stores hibernated cell state as `.hibernated` snapshot files on local disk, allowing cells to rehydrate without re-executing their constructors.**

The **local cache mechanism for hibernated cells** in Celld (denoland/celld) minimizes cold-start latency by persisting a cell's SQLite database state to disk when its only remaining live resources are hibernatable WebSocket streams. This design lets the runtime restore cells instantly rather than rebuilding them from scratch.

## How Hibernation Triggers Cache Creation

A cell enters the hibernated state when `Core::is_hibernated` determines that all active resources can be safely suspended. In [`crates/logic/lib.rs`](https://github.com/denoland/celld/blob/main/crates/logic/lib.rs), this check examines whether remaining WebSocket streams are marked hibernatable:

```rust
// crates/logic/lib.rs – pub fn is_hibernated(&self, id: &str) -> bool
pub fn is_hibernated(&self, id: &str) -> bool {
    // Returns true when only hibernatable resources remain,
    // signaling the cell can be cached rather than destroyed
}

```

When `is_hibernated` returns `true`, the cell transitions to hibernated status while its SQLite record persists on disk.

## The .hibernated Snapshot File Format

The **state store**—the cell's SQLite database—contains all durable data. Upon hibernation, Celld writes a **snapshot cache** file with the `.hibernated` extension.

In [`crates/celld/ltx_repl.rs`](https://github.com/denoland/celld/blob/main/crates/celld/ltx_repl.rs) (lines 406-416), the runtime:
- Copies the SQLite database file
- Flushes and includes any pending **WAL (Write-Ahead Log)** data
- Packages this into the atomic `.hibernated` snapshot

This ensures the snapshot represents a consistent, recoverable state.

## Cache Lookup and Cell Rehydration

When a new event arrives for a hibernated cell, the dispatch logic in [`crates/celld/main.rs`](https://github.com/denoland/celld/blob/main/crates/celld/main.rs) (lines 2770-3305) performs a **local cache lookup**:

1. Check for existing `.hibernated` file
2. Validate snapshot integrity
3. **Rehydrate** directly from cache if valid
4. Fall back to fresh construction if validation fails

```rust
// Simplified representation of the dispatch decision flow
fn dispatch_event(cell_id: &str, event: Event) {
    if core.is_hibernated(cell_id) {
        // Attempt cache-based restore
        if let Some(snapshot) = load_hibernated_snapshot(cell_id) {
            restore_from_snapshot(cell_id, snapshot);
            return;
        }
    }
    // Fresh start path
    spawn_new_isolate(cell_id, event);
}

```

## Cache Eviction and Size Management

The **local cache mechanism** is not permanent. The `logic::cache` module enforces **size-based eviction policies** to prevent disk exhaustion:

```rust
// Rust: manual cache eviction (normally triggered internally)
core.evict_cache_until_size(50 * 1024 * 1024); // enforce 50 MiB limit

```

In [`crates/logic/cache.rs`](https://github.com/denoland/celld/blob/main/crates/logic/cache.rs) (lines 11-30), the eviction algorithm prunes oldest snapshots first when cache size exceeds configured thresholds.

## Safety Checks and Invalidation

Before using a cached snapshot, Celld validates consistency with current replication state. The `invalidate_pos_cache` logic in [`crates/ltx/src/db.rs`](https://github.com/denoland/celld/blob/main/crates/ltx/src/db.rs) (lines 495-511) verifies:

- Snapshot matches current **replication position**
- No **unsafe writes** occurred since hibernation
- Database checksums align with expected values

If validation fails, the cache is discarded and the cell rebuilds from scratch—a slower but safe fallback.

## JavaScript API for Hibernatable Detection

Cell authors can check hibernatability status via the `celld:js/websocket` module:

```javascript
// JavaScript: check if a cell can hibernate (indicating cache may exist)
import { ws_hibernatable } from "celld:js/websocket";

const cellId = 42;
const canHibernate = ws_hibernatable(cellId).unwrapOr(false);
console.log(`Cell ${cellId} hibernatable?`, canHibernate);

```

This API surfaces the same hibernatability check used internally by the runtime to trigger `.hibernated` snapshot creation.

## Key Source Files

| File | Responsibility |
|------|--------------|
| [`crates/logic/lib.rs`](https://github.com/denoland/celld/blob/main/crates/logic/lib.rs) | Core hibernation detection (`is_hibernated`) |
| [`crates/celld/ltx_repl.rs`](https://github.com/denoland/celld/blob/main/crates/celld/ltx_repl.rs) | `.hibernated` snapshot read/write operations |
| [`crates/celld/main.rs`](https://github.com/denoland/celld/blob/main/crates/celld/main.rs) | Event dispatch and cache-vs-fresh restore decisions |
| [`crates/logic/cache.rs`](https://github.com/denoland/celld/blob/main/crates/logic/cache.rs) | Size-based eviction for snapshot cache |
| [`crates/ltx/src/db.rs`](https://github.com/denoland/celld/blob/main/crates/ltx/src/db.rs) | Position validation and cache invalidation |
| [`crates/celld/js/websocket.rs`](https://github.com/denoland/celld/blob/main/crates/celld/js/websocket.rs) | JavaScript hibernatable WebSocket API |

## Summary

- **Hibernation trigger**: `Core::is_hibernated` in [`crates/logic/lib.rs`](https://github.com/denoland/celld/blob/main/crates/logic/lib.rs) identifies when cells can suspend
- **Cache format**: `.hibernated` files containing SQLite state plus WAL data
- **Fast restore**: [`crates/celld/main.rs`](https://github.com/denoland/celld/blob/main/crates/celld/main.rs) dispatch logic rehydrates from cache when valid
- **Resource limits**: `logic::cache` enforces automatic eviction by total size
- **Safety**: [`ltx/src/db.rs`](https://github.com/denoland/celld/blob/main/ltx/src/db.rs) validates snapshots against replication state before use

## Frequently Asked Questions

### What distinguishes a hibernated cell from a destroyed cell?

A **destroyed cell** has no persisted state and must re-execute its constructor on next access. A **hibernated cell** maintains its `.hibernated` snapshot on local disk, enabling sub-second reactivation without constructor re-execution. The key difference is the presence of a valid cache file that passed all safety checks.

### How does Celld prevent cache corruption from replication lag?

Before rehydration, `invalidate_pos_cache` in [`crates/ltx/src/db.rs`](https://github.com/denoland/celld/blob/main/crates/ltx/src/db.rs) compares the snapshot's replication position against the current cluster state. If the cell processed transactions that the snapshot doesn't include, or vice versa, the cache is invalidated and the cell rebuilds from durable SQLite storage instead.

### Can I configure the local cache size limit?

The eviction threshold is controlled through `core.evict_cache_until_size()`, typically invoked internally by the runtime based on node configuration. Direct manipulation requires Rust-level access to the `Core` struct; there is presently no JavaScript API for cache sizing.

### What happens to WebSocket connections during hibernation?

Hibernatable WebSocket connections, configured via `ws_hibernatable()` in [`crates/celld/js/websocket.rs`](https://github.com/denoland/celld/blob/main/crates/celld/js/websocket.rs), are the prerequisite for hibernation itself. These connections enter a suspended state tracked separately; when the cell rehydrates, Celld attempts to resume them transparently if the underlying transport remains valid.