How the Cache Controller Works in Music Assistant: Implementation and API Guide

The Cache Controller in Music Assistant is a JSON-based key-value store that uses SQLite for persistence, providing async methods for get/set/delete operations, automatic expiration handling, and a bypass mechanism for forced refresh operations.

The cache controller is a core component of the music-assistant/server repository, providing a lightweight, JSON-based key-value store for the entire Music Assistant application. Located in music_assistant/controllers/cache/controller.py, this async-friendly caching layer centralizes data persistence, expiration management, and schema migration to ensure optimal performance across the platform.

Architecture and Storage Backend

SQLite Database Implementation

The cache controller persists all data to an SQLite file named cache.db located in the user's cache directory. During initialization, the controller calls __create_database_tables and __create_database_indexes to establish the required schema and optimize query performance.

Schema versioning is handled through the _setup_database method, which reads the stored version from DB_TABLE_SETTINGS and compares it against DB_SCHEMA_VERSION. When versions differ, __migrate_database executes the necessary ALTER statements—for example, adding the allow_expired_cache column to existing tables.

Core API Methods

Retrieving Cached Data

The get method in music_assistant/controllers/cache/controller.py retrieves values by key while handling JSON deserialization, optional checksum validation, and expiration checks. If the cached entry is expired and allow_expired_cache is disabled, the method returns the default value.

top_tracks = await mass.cache.get(
    key="artist_top_tracks",
    provider="spotify",
    category=1,
    default=[],
)

Storing Data with Metadata

The set method handles JSON serialization and accepts parameters for time-to-live (TTL), provider identification, category classification, checksums, and persistence flags. The expiration parameter defines the TTL in seconds, while persistent entries survive cleanup operations.

await mass.cache.set(
    key="artist_top_tracks",
    data=["track1", "track2", "track3"],
    expiration=3600,  # 1 hour TTL

    provider="spotify",
    category=1,
)

Cache Invalidation

The controller provides two removal mechanisms: delete for specific keys and clear for bulk operations. The clear method supports filtering by provider and includes a boolean include_persistent flag to protect persistent entries during cleanup.


# Clear only non-persistent entries for a specific provider

await mass.cache.clear(
    provider_filter="spotify",
    include_persistent=False,
)

Advanced Features

Checksum-Based Validation

To prevent stale data usage, the controller supports optional checksums. When setting data, you provide a checksum string; when retrieving, you specify the expected checksum. If the stored checksum differs from the provided value, the get method returns the default.

checksum = "v5"
await mass.cache.set(
    key="playlist_42",
    data=playlist_dict,
    checksum=checksum,
)

# Returns None if checksum doesn't match

cached = await mass.cache.get(
    key="playlist_42",
    checksum="v5",
    default=None,
)

Cache Bypass Context Manager

The handle_refresh context manager temporarily toggles the BYPASS_CACHE thread-local flag defined in music_assistant/controllers/cache/constants.py. Within this context, all get operations return the default value, forcing fresh data fetches while allowing set operations to populate the cache with updated values.

async with mass.cache.handle_refresh(bypass=True):
    fresh_data = await fetch_latest_data()
    await mass.cache.set(key="latest", data=fresh_data)

Automatic Maintenance and Cleanup

Background Cleanup Task

The _register_cleanup_task method schedules a daily background task that executes auto_cleanup. This routine deletes rows where the expires timestamp has passed, unless the entry is marked with allow_expired_cache. The controller also monitors the database file size against MAX_CACHE_DB_SIZE_MB and issues warnings when limits are exceeded.

Configuration Interface

The controller exposes a configuration entry CONF_CLEAR_CACHE that appears in the Music Assistant UI. When invoked through the interface, this triggers the clear() method to wipe the cache.

Key Files and Module Structure

The cache subsystem spans four primary files:

Summary

  • The cache controller uses SQLite (cache.db) for persistent JSON storage, with automatic table creation and index optimization via __create_database_tables and __create_database_indexes.
  • Public async methods get, set, delete, and clear provide full CRUD operations with support for TTL, checksums, and provider-based filtering.
  • Schema migrations are handled automatically through __migrate_database when DB_SCHEMA_VERSION differs from the stored version.
  • The handle_refresh context manager enables temporary cache bypassing using the BYPASS_CACHE thread-local flag.
  • Automatic maintenance runs daily via auto_cleanup, removing expired entries while respecting allow_expired_cache flags and monitoring database size limits.

Frequently Asked Questions

Where is the cache data physically stored?

The cache controller stores all data in an SQLite file named cache.db located in the user's cache directory. This file is created automatically when the controller initializes, and its schema is managed through the _setup_database and __migrate_database methods in music_assistant/controllers/cache/controller.py.

How does the cache handle schema updates?

When the controller initializes, it reads the stored schema version from DB_TABLE_SETTINGS and compares it to DB_SCHEMA_VERSION defined in the constants. If versions differ, __migrate_database executes the required ALTER statements to update the database structure without losing existing cached data.

Can I force a cache refresh while bypassing stored values?

Yes. Use the handle_refresh context manager, which sets the BYPASS_CACHE thread-local flag. While inside this context, get operations will return default values, allowing you to fetch fresh data and repopulate the cache. This is particularly useful for "refresh-only" UI actions.

What triggers automatic cache cleanup?

A daily background task registered via _register_cleanup_task executes auto_cleanup, which deletes rows where the expires timestamp has passed. Entries marked with allow_expired_cache are preserved. The controller also checks the database file size against MAX_CACHE_DB_SIZE_MB and logs warnings if the limit is exceeded.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →