Skip to content

Caching and State

Anatoliy Ivanov edited this page Jul 19, 2026 · 1 revision

Caching and State

folea keeps application state in Electron's userData directory and vault-specific state under <vault>/.folea/.

Path Contents
<userData>/state.json Last-opened vault and recent vaults
<vault>/.folea/state.json Last note, recent notes, positions, palette history, template choice
<vault>/.folea/render-cache/ Persistent compiled Typst results
<userData>/prefs.config Global preferences; not cleared with caches
<vault>/.folea/prefs.config Vault preference overrides; not cleared with caches

Platform-specific userData locations are listed in Configuration.

Application state

Global state.json stores:

  • the last-opened vault
  • up to 10 recent vault paths
  • an update timestamp

Opening a vault moves it to the front of the recent list and saves it as the last vault. Closing a vault does not clear that last path. Removing the same vault from the recent list does clear it as the last vault.

If the file is unreadable, invalid JSON, or an unsupported schema, folea tries to rename it to:

state.json.corrupt-<timestamp>

It then starts with no saved vaults.

Vault reading state

Vault .folea/state.json stores:

State Limit or behavior
Last-opened note One path
Recent notes Up to 50
Per-note positions Up to 1,000
Palette command history Up to 50; palette-accepted actions only
Last creation template One direct _templates/*.typ path, or none

A note position includes vertical and horizontal scroll, viewport and content height, proportional scroll, zoom mode, zoom level, and a timestamp. The schema has caretSpanIndex, but the current app saves it as null; caret placement is not restored.

Position changes are saved after a 500 ms delay. Navigating away or closing a vault saves the pending position immediately.

When restoring scroll, folea uses the saved absolute position if it still fits. Otherwise it uses the saved ratio. Notes without saved zoom start at:

mode = fitWidth
level = 1

Managed moves and renames update saved paths. Missing and deleted notes are removed from saved recent-note and position entries.

If the whole vault state file is unreadable or has an unsupported schema, folea tries to rename it to:

<vault>/.folea/state.json.corrupt-<timestamp>

Invalid individual recent-note or position entries are skipped. State writes use a temporary file followed by rename.

Persistent render cache

Compiled results are stored under:

<vault>/.folea/render-cache/
├── manifest.json
└── entries/
    └── <sha256>.json

An entry contains the rendered SVG artifact, searchable text layer, and heading outline.

A cached result is accepted only when:

  • its source/path cache key matches
  • its renderer and compiler versions match the current app
  • every recorded source, import, and include still exists
  • every recorded input still has the same SHA-256 content hash

Checking a persistent hit still reads and hashes recorded input files. The cache avoids Typst compilation; it does not avoid all disk I/O.

Stale, corrupt, or version-mismatched entries are skipped. folea compiles the note again and can replace the entry after a successful render. A cache-write failure does not block the visible document.

The cache holds at most 500 entries and 250 MiB. When either limit is exceeded, the least recently used entries are removed first.

Warmup and prefetch

About 500 ms after a vault refresh, a separate worker attempts to warm every indexed note. Order is:

  1. current note
  2. recent notes
  3. remaining notes in path order

Valid persistent hits are skipped. Misses compile one at a time. One broken note is logged and skipped; it does not stop the rest of the queue. The status line shows render cache <done>/<total> while warmup runs.

Keeping a tree row highlighted for about 120 ms schedules a one-at-a-time prefetch. This can make the note open faster without changing the visible document.

The compile worker also keeps 32 rendered artifacts in memory. This cache disappears when the worker exits or receives a fresh vault snapshot.

Live invalidation

The watcher handles normal .typ files outside ignored directories. A source edit invalidates that note. A changed import or include also invalidates notes that depend on it. An unrelated watched note does not force every note to recompile.

Ignored directories are not watched:

.obsidian
.git
node_modules
.folea
.folea-cache
_templates

After editing a render dependency in one of those directories, close and reopen the vault so folea rebuilds the render snapshot and rechecks cache hashes.

Clear caches

Open the command palette with :.

Command What it clears What it keeps
Clear current vault cache (cache.clearCurrentVault) <vault>/.folea/render-cache/; current warmup/prefetch and worker entries Vault state and preferences
Clear application cache (cache.clearApplication) Electron web cache and code caches Vault render caches, state, and preferences

Neither command resets recent vaults, reading positions, theme, editor settings, or key bindings.

Clone this wiki locally