Folia IndexedDB Schema: Inside KineticPlayerDB’s Six Object Stores

Folia persists runtime data in a version 5 IndexedDB database named KineticPlayerDB that contains six specialized object stores—session, api_cache, user_cache, media_cache, metadata_cache, and local_music—each optimized for specific data types ranging from transient session state to binary media blobs and locally imported tracks.

The open-source Folia project (chthollyphile/folia-major) implements a robust client-side storage layer using IndexedDB to manage everything from temporary UI variables to persistent local music libraries. The complete schema definition and migration logic reside in src/services/db.ts, where the database is initialized with automatic versioning that handles seamless upgrades from legacy schema versions.

Database Configuration and Versioning

The IndexedDB schema is anchored by constants defined at the top of src/services/db.ts (lines 7–15):

const DB_NAME = 'KineticPlayerDB';
const DB_VERSION = 5;
const STORE_NAME = 'session';
const CACHE_STORE = 'api_cache';
const USER_CACHE_STORE = 'user_cache';
const MEDIA_CACHE_STORE = 'media_cache';
const METADATA_CACHE_STORE = 'metadata_cache';
const LOCAL_MUSIC_STORE = 'local_music';

The database opens with an onupgradeneeded handler that branches on oldVersion to create stores incrementally. This ensures that users migrating from earlier installs receive the full schema without data loss.

The Six Object Stores

Folia separates concerns across six distinct object stores, each with specific key paths and data interfaces.

session

The session store holds transient runtime information such as the current audio file, active lyrics, theme preferences, and cached AI backgrounds. Unlike other stores, it uses no explicit key path; instead, keys are supplied explicitly during put operations.

  • Key path: None (explicit key per entry)
  • Interface: SessionData
  • Fields: audioFile?, fileName?, lyricId?, lyrics?, theme?, cachedAiBg?, coverUrl?, timestamp?

api_cache

The api_cache store maintains backward-compatible caching for legacy keys like last_song, last_queue, and last_theme. It serves as a general-purpose key-value cache with a standardized shape.

  • Key path: key
  • Interface: CacheData
  • Shape: { key: string, data: any, timestamp: number }

user_cache

Introduced in schema versions below 3, the user_cache store migrates user-related objects from the legacy api_cache store. It holds profiles, playlists, liked songs, and cloud playlist data using the same CacheData interface.

  • Key path: key
  • Interface: CacheData
  • Migration: Existing user data moves from api_cache to user_cache during upgrades

media_cache

The media_cache store manages binary blobs for media assets, including audio files (prefixed with audio_*) and cover images (prefixed with cover_*). These are stored directly as blobs within the CacheData wrapper.

  • Key path: key
  • Content: Binary audio and image data
  • Naming convention: audio_* for tracks, cover_* for artwork

metadata_cache

The metadata_cache store indexes lyric files, theme definitions, and playlist details. Keys follow strict prefixes to distinguish entity types: lyric_ for lyrics, theme_ for themes, playlist_tracks_ for track listings, and playlist_detail_ for playlist metadata.

  • Key path: key
  • Interface: CacheData
  • Key prefixes: lyric_, theme_, playlist_tracks_, playlist_detail_

local_music

The local_music store is the only schema element using a custom key path. It persists locally imported songs with a structured LocalSong interface defined in src/types.ts. Each entry carries its own unique identifier, making it suitable for primary key indexing.

  • Key path: id
  • Interface: LocalSong
  • Created: Version 4 and above (lines 103–107 in src/services/db.ts)

Schema Migration Logic

The onupgradeneeded handler in openDB implements incremental migration:

  1. Base stores: Ensures session and api_cache exist with { keyPath: 'key' } for the cache store.
  2. Version < 3: Adds user_cache, media_cache, and metadata_cache if upgrading from legacy installs.
  3. Version 4+: Creates local_music with { keyPath: 'id' }.

During upgrades from pre-version 3, the code explicitly migrates legacy user data from api_cache to user_cache, ensuring continuity without duplicate entries.

Working with the Schema

The following patterns demonstrate how to interact with the IndexedDB schema using the helper functions exported from src/services/db.ts:

import {
  openDB,
  saveSessionData,
  getSessionData,
  saveLocalSong,
  getLocalSongs,
  saveToCache,
  getFromCache,
} from '@/services/db';

// Open the database (typically handled automatically by helpers)
const db = await openDB();

// Store transient session data
await saveSessionData('coverUrl', 'https://example.com/cover.png');

// Retrieve the complete session object
const session = await getSessionData();

// Cache an API response in the user_cache store
await saveToCache('last_song', { title: 'Demo Track', artist: 'Example Artist' });

// Read cached values with type safety
const lastSong = await getFromCache<{title: string; artist: string}>('last_song');

// Persist a local song to the local_music store
await saveLocalSong({
  id: 'song-123',
  title: 'My Track',
  // ... other LocalSong fields
});

// Fetch all locally stored songs
const localSongs = await getLocalSongs();

Summary

  • Folia IndexedDB schema centers on a single database named KineticPlayerDB at version 5, defined in src/services/db.ts.
  • Six object stores handle distinct responsibilities: session for transient state, api_cache for legacy compatibility, user_cache for user objects, media_cache for binary blobs, metadata_cache for lyrics and themes, and local_music for imported tracks.
  • Versioned migrations automatically create stores and migrate legacy data when users upgrade the application.
  • Consistent interfaces: Five stores use the CacheData shape with a key primary key, while local_music uses the LocalSong interface with an id key path.
  • Type definitions for all data shapes reside in src/types.ts.

Frequently Asked Questions

What is the name and current version of Folia's IndexedDB database?

The database is named KineticPlayerDB and currently runs at version 5. These constants are hardcoded in src/services/db.ts and drive the onupgradeneeded migration logic.

How does Folia handle schema upgrades when the stored version is outdated?

Folia implements an onupgradeneeded handler that checks oldVersion and incrementally creates missing stores. For versions below 3, it adds user_cache, media_cache, and metadata_cache. For version 4 and above, it creates the local_music store. Legacy user data automatically migrates from api_cache to user_cache during these upgrades.

Why does the local_music store use a different key path than the other stores?

The local_music store uses { keyPath: 'id' } because it stores LocalSong objects that already contain unique identifiers. All other stores use a generic { keyPath: 'key' } configuration with a CacheData wrapper, allowing flexible string-based lookups for cached blobs and metadata.

Where are binary audio files and cover images stored in the Folia IndexedDB schema?

Binary media assets reside in the media_cache store. Audio files are stored with keys prefixed by audio_*, while cover images use the cover_* prefix. Both are wrapped in the standard CacheData interface and stored as Blob objects.

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 →