Files
CherryHQ-cherry-studio/docs/references/data/boot-config-overview.md
fullex c514dcc049 refactor(shared): move packages/shared to src/shared
packages/shared was never a real pnpm workspace package (no package.json); it was referenced only through the @shared TypeScript path alias. Relocate it under src/ via git mv (143 files, detected as pure renames).

Repoint the @shared alias and include globs to src/shared across electron.vite.config.ts, tsconfig.{json,node,web}.json and vitest.config.ts; update scripts/check-custom-exts.ts, scripts/update-languages.ts, the eslint.config.mjs generated-file globs, the data-classify generator output targets, .github/CODEOWNERS path rules, and CLAUDE.md/docs/source-comment references.

The @shared alias name is unchanged, so all 1403 @shared/* import sites resolve without modification. Verified with typecheck:node, typecheck:web and the full test suite (700 files, 9739 tests passing).
2026-05-28 21:02:49 -07:00

13 KiB

Boot Config System Overview

The Boot Config system provides synchronous, file-based configuration for settings that must be available before the application lifecycle takes over — before the database, before PreferenceService, before any lifecycle phase runs.

Purpose

BootConfigService handles data that:

  • Must be loaded synchronously at process startup (before any async initialization)
  • Affects process-level behavior that cannot be changed at runtime (e.g., Chromium flags)
  • Cannot wait for database initialization (SQLite is not yet available)
  • Needs to be read before the lifecycle system's BeforeReady phase

Typical examples: disabling hardware acceleration, setting user data directory paths, configuring Chromium command-line switches.

Boot Timing

┌──────────────────────────────────────────────────────────────────────┐
│ App Startup Sequence                                                 │
│                                                                      │
│  1. BootConfig load        ← Sync read of boot-config.json           │
│     (bootConfigService)      Only data system available here         │
│          │                                                           │
│  2. Bootstrap              ← App data directory setup                │
│          │                                                           │
│  3. application.bootstrap()                                          │
│          │                                                           │
│          ├── Background phase (fire-and-forget)                      │
│          │                                                           │
│          ├── Promise.all([                                           │
│          │     BeforeReady phase,  ← DB init, PreferenceService,     │
│          │     app.whenReady()       CacheService, DataApiService    │
│          │   ])                                                      │
│          │                                                           │
│          └── WhenReady phase       ← Window creation, IPC handlers   │
│                                                                      │
└──────────────────────────────────────────────────────────────────────┘

BootConfig is the only data system available at stage 1 — before the lifecycle system takes over. The BeforeReady phase and app.whenReady() run in parallel (via Promise.all); once both complete, WhenReady services start. From the BeforeReady phase onward, boot config values are also accessible through PreferenceService via the BootConfig.* prefix.

Key Characteristics

Synchronous Loading

  • Reads boot-config.json via fs.readFileSync on module import
  • No async, no promises — values available immediately at the top of src/main/index.ts
  • If the file is missing (first launch), falls back to defaults
  • If the file is corrupt, records the error — the app should not continue with corrupted boot config

Flat Key-Value Structure

Keys follow the same naming convention as preferences: namespace.key_name

Key Type Default Description
app.disable_hardware_acceleration boolean false Disable Chromium hardware acceleration

Atomic File Writes

  • Writes to a temp file first, then renames to boot-config.json
  • Prevents corruption from crashes during write

Debounced Saving

  • Writes are debounced by 500ms to coalesce rapid changes
  • flush() forces an immediate write (used on app quit)

Error Handling

  • Tracks load errors: parse_error (invalid JSON) or read_error (file inaccessible)
  • Missing file (first launch): falls back to DefaultBootConfig — this is normal
  • Corrupt file: records the error via loadError. The app should check hasLoadError() and abort startup rather than continue with potentially incorrect configuration
  • Errors can be inspected via hasLoadError() / getLoadError() / clearLoadError()

Architecture

┌─────────────────────────────────────────────────────────────────┐
│ Early Boot (before lifecycle)                                   │
│                                                                 │
│  src/main/index.ts                                              │
│       │                                                         │
│       ▼                                                         │
│  bootConfigService.get('app.disable_hardware_acceleration')     │
│       │              ▲                                          │
│       ▼              │                                          │
│  ┌───────────────────┴──────────────────┐                       │
│  │ BootConfigService                    │                       │
│  │ - Sync load on import                │                       │
│  │ - In-memory config map               │◄──── boot-config.json │
│  │ - Debounced save                     │      (~/.cherrystudio/)│
│  └──────────────────────────────────────┘                       │
└─────────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────────┐
│ After Lifecycle Starts                                          │
│                                                                 │
│  Renderer                          Main Process                 │
│  ┌──────────────────┐              ┌──────────────────────────┐ │
│  │ usePreference    │    IPC       │ PreferenceService        │ │
│  │ ('BootConfig.*') │─────────────►│ detects BootConfig.*     │ │
│  └──────────────────┘              │ prefix, routes to        │ │
│                                    │ bootConfigService        │ │
│                                    └──────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘

BootConfig also carries data migrated from v1's ~/.cherrystudio/config/config.json file (see BootConfigMigrator's file source). The app.user_data_path key holds the custom user data directory mapping that the v1 file stored under appDataPath. Long-term, BootConfig will fully replace the legacy config/config.json — the follow-up PR will rewire initAppDataDir() to read app.user_data_path from BootConfig instead of parsing the legacy file directly.

Access Convention

Context API Note
Early boot (before lifecycle) bootConfigService.get(key) / .set(key, value) Only option — DB and lifecycle not yet available
Lifecycle services (Main) preferenceService.get('BootConfig.*') Standardized; enables cross-window sync
Renderer (React components) usePreference('BootConfig.*') Same as regular preference usage

Rule: Once the lifecycle is running, always access boot config values through PreferenceService. Direct bootConfigService usage is reserved exclusively for early boot code.

For detailed usage of usePreference and preferenceService, see Preference Usage Guide.

BootConfig vs Preference

Aspect BootConfig Preference
Loading Synchronous, before lifecycle takes over Async, at BeforeReady phase (parallel with app.whenReady())
Storage boot-config.json (filesystem) SQLite database
Availability From process start After DB initialization
Use case Process-level flags, Chromium switches User-modifiable app settings
Cross-window sync Via PreferenceService delegation Native
Key count Minimal (process-level only) 158+ keys

PreferenceService Integration

Boot config keys are accessible through PreferenceService using the BootConfig. prefix:

  • preferenceService.get('BootConfig.app.disable_hardware_acceleration') routes to bootConfigService.get('app.disable_hardware_acceleration')
  • The BootConfigPreferenceKeys mapped type automatically adds the BootConfig. prefix to all boot config keys
  • The UnifiedPreferenceType merges both preference and boot config type spaces, providing full type safety
  • Changes made through PreferenceService are broadcast to all windows

Utility functions in src/shared/data/preference/preferenceUtils.ts:

Function Purpose
isBootConfigKey(key) Check if a key has the BootConfig. prefix
toBootConfigKey(key) Strip BootConfig. prefix to get the underlying key
getDefaultValue(key) Unified default lookup for both preference and boot config keys

File Storage

  • Path: ~/.cherrystudio/boot-config.json (intentionally outside userData)
  • Format: Flat JSON object, pretty-printed (2-space indent)

Why outside userData? Boot config must be readable before the app data directory is determined. Storing it under userData would create a chicken-and-egg problem: the file that decides where data lives cannot itself live inside that data. Placing it under ~/.cherrystudio/ keeps it stable across changes to appDataPath and ensures it is always available at process start, before initAppDataDir() runs.

{
  "app.disable_hardware_acceleration": false,
  "app.user_data_path": {
    "/Applications/Cherry Studio.app/Contents/MacOS/Cherry Studio": "/Volumes/External/CherryData"
  }
}

app.user_data_path is a Record<executablePath, dataPath> keyed by the executable path — same-machine multiple installations (stable / dev / portable) can each have their own user data directory, matching the semantic of v1's appDataPath array.

File Purpose
src/main/data/bootConfig/BootConfigService.ts Core service — sync load, debounced save, change notifications
src/main/data/bootConfig/types.ts BootConfigLoadError type definition
src/shared/data/bootConfig/bootConfigSchemas.ts BootConfigSchema interface and DefaultBootConfig
src/shared/data/bootConfig/bootConfigTypes.ts BootConfigKey, BootConfigPreferenceKeys mapped type
src/shared/data/preference/preferenceUtils.ts BootConfig.* prefix routing utilities
src/main/data/PreferenceService.ts Routes BootConfig.* keys to bootConfigService
src/main/index.ts Early boot usage (first import, hardware acceleration check)