Skip to content

App Cache

self.cache provides persistent key-value storage on every App instance — no setup required. Data written to the cache survives restarts and is available at the next startup. The cache is a diskcache.Cache instance backed by a third-party disk-based storage library. The full diskcache API is available directly.

For real-time Home Assistant entity state, self.states (the local state cache) is the right tool. self.cache is for app data: counters, timestamps, API responses, preferences.

Basic Usage

The cache exposes a dictionary-like API for get, set, delete, and membership checks. No open, flush, or close call is needed.

from hassette import App, AppConfig


class MyApp(App[AppConfig]):
    async def on_initialize(self):
        # Store data
        self.cache["last_run"] = self.now()
        self.cache["user_preferences"] = {"theme": "dark", "notifications": True}

        # Retrieve data
        if "last_run" in self.cache:
            last_run = self.cache["last_run"]
            self.logger.info("Last run: %s", last_run)

        # Get with default value
        count = self.cache.get("run_count", 0)
        self.cache["run_count"] = count + 1

        # Delete data
        if "old_key" in self.cache:
            del self.cache["old_key"]

Hassette opens the cache at first access and flushes it to disk at shutdown. All reads and writes happen transparently in between.

Shared Cache and Multi-Instance Apps

All instances of the same app class share one cache directory, keyed by class name. Two instances of WeatherApp with different configurations read from and write to the same cache.

Hassette can run the same app class multiple times with different configs (see App Instances). For multi-instance apps, prefixing keys with self.app_config.instance_name (automatically set from the [apps.<key>] identifier in hassette.toml) avoids collisions:

from hassette import App, AppConfig


class MyApp(App[AppConfig]):
    async def on_initialize(self):
        # Prefix keys with instance_name to avoid collisions
        # when the same app class runs as multiple instances
        cache_key = f"{self.app_config.instance_name}:last_run"
        self.cache[cache_key] = self.now()

What Can Be Cached

The cache stores any Python object that supports pickling, Python's built-in serialization format. This includes:

  • Primitives: str, int, float, bool, None
  • Collections: list, dict, tuple, set
  • Timestamps from the whenever library (Hassette's date/time library): Instant, ZonedDateTime, PlainDateTime, TimeDelta
  • Pydantic models and dataclasses (if picklable)

Storing timestamps

self.now() — a built-in App method returning the current time as a timezone-aware ZonedDateTime — and all whenever types are picklable. Store them directly in the cache without conversion.

Configuration

default_cache_size and data_dir are root-level settings in hassette.toml:

[hassette]
default_cache_size = 104857600  # 100 MiB (default)
data_dir = "/path/to/data"
Setting Type Default Description
default_cache_size integer (bytes) 104857600 Size limit for each app's cache. Least-recently-used items are evicted when the limit is reached.
data_dir path platform-dependent Root directory for all persistent data. See Global Settings for platform defaults.

How It Works

Storage location. Each app's cache lives at {data_dir}/{ClassName}/cache/. A WeatherApp with data_dir = /home/user/.hassette stores its cache at /home/user/.hassette/WeatherApp/cache/.

Lazy initialization. The cache directory is created on first access. Apps that never use self.cache produce no directory.

Lifecycle. The cache is available from first access through shutdown. Hassette closes and flushes it to disk when the app stops.

Automatic cleanup. Entries with a TTL expire silently. When the cache reaches its size limit (the default_cache_size setting), the least-recently-used items are evicted without raising an error. To set a TTL, use self.cache.set() instead of bracket assignment:

self.cache.set("weather_data", payload, expire=3600)  # expires after 1 hour

Verify It Works

Check that cache data persists across restarts with hassette log:

hassette log --app my_app --since 1h

Set log_level = "DEBUG" in hassette.toml first — cache reads and writes only appear in the log at that level. The cache directory at {data_dir}/{ClassName}/cache/ contains SQLite files managed by diskcache after the first successful write; the filenames are internal, not meant for inspection.

See Also