Skip to content

perf: cache loadConfig() and ensureConfigDir() results to eliminate repeated disk reads - #25

Open
mediumWellness wants to merge 1 commit into
veniceai:mainfrom
mediumWellness:perf/cache-loadconfig
Open

perf: cache loadConfig() and ensureConfigDir() results to eliminate repeated disk reads#25
mediumWellness wants to merge 1 commit into
veniceai:mainfrom
mediumWellness:perf/cache-loadconfig

Conversation

@mediumWellness

Copy link
Copy Markdown

Problem

Every CLI command caused multiple synchronous disk reads via \loadConfig(). The call chain for each output line alone was:

\
getChalk() → createChalk() → isColorEnabled() → loadConfig() → fs.readFileSync()
\\

Beyond that, \getDefaultModel(), \getDefaultImageModel(), \getDefaultVoice(), \getApiKey(), \shouldShowUsage(), and \getOutputFormat()\ each independently called \loadConfig(), meaning a single command could trigger 6+ synchronous
eadFileSync\ calls
reading the same file each time.

Similarly, \ensureConfigDir()\ called \ s.existsSync(CONFIG_DIR)\ on every config/history/usage operation with no early-exit.

Fix

Added two module-level caches in \src/lib/config.ts:

Config cache

\\ s
let _configCache: VeniceConfig | null = null;
\\

  • \loadConfig()\ returns the cached value immediately on every call after the first
  • \saveConfig()\ updates _configCache\ after writing to disk so the cache stays in sync
  • \deleteConfigValue()\ goes through \saveConfig(), so it also keeps the cache correct

Config-dir flag

\\ s
let _configDirEnsured = false;
\\

  • \ensureConfigDir()\ returns early after the first successful call, skipping the \ s.existsSync\ check on every subsequent invocation

Expected improvement

After this change, \loadConfig()\ incurs a single
eadFileSync\ per process lifetime instead of one per call site. For a typical command that calls 6+ config accessor functions, this reduces synchronous I/O from O(N) to O(1).

Testing

Existing test suite passes (
pm test) — one test covering \config show --format json\ with API key masking.

…epeated disk reads

Add module-level in-memory caches for both config loading and
config-dir creation to avoid redundant synchronous fs operations
on every CLI command invocation.

- _configCache: VeniceConfig | null — populated on first loadConfig()
  call; returned directly on subsequent calls; updated by saveConfig()
  so it stays in sync after writes
- _configDirEnsured: boolean — set to true after the first successful
  ensureConfigDir(); subsequent calls return immediately without
  an fs.existsSync() round-trip

Before this change every output line triggered:
  getChalk() -> createChalk() -> isColorEnabled() -> loadConfig() -> fs.readFileSync()
and each of getDefaultModel(), getDefaultImageModel(), getDefaultVoice(),
getApiKey(), shouldShowUsage(), getOutputFormat() also called loadConfig()
independently, causing N synchronous disk reads per invocation.

After this change only the first call incurs any I/O.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings August 3, 2026 16:18

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR reduces repeated synchronous filesystem access in the CLI by introducing in-process caching for configuration loading and a one-time guard for ensuring the config directory exists.

Changes:

  • Add a module-level _configCache so loadConfig() reads/parses config.json at most once per process.
  • Update saveConfig() to keep the in-memory cache in sync after writes.
  • Add a module-level _configDirEnsured flag so ensureConfigDir() avoids repeated existsSync() checks.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/lib/config.ts
Comment on lines 38 to +42
} catch {
// Return empty config on error
}
return {};
_configCache = {};
return _configCache;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants