Skip to content

perf(desktop): replace electron-store with a plain JSON settings store - #49791

Merged
Hona merged 1 commit into
v2from
settings-store
Sep 18, 2026
Merged

Hona merged 1 commit into
v2from
settings-store

Conversation

@Hona

@Hona Hona commented Sep 18, 2026

Copy link
Copy Markdown
Member

Chromium startup trace of a packaged launch, browser process, require() events (ms since trace start):

146  ajv/dist/2020.js        ┐
153  fast-deep-equal          │ electron-store → conf → ajv, ajv-formats,
156  fast-uri                 │ semver, dot-prop, …
171  ajv-formats              │
172  semver                   ┘
182  electron-log

The main process uses three methods of electron-store — get, set, delete — on two tab-indented JSON files (opencode.settings, opencode.updater). Importing it cost ~36 ms of CommonJS loading on every launch before any of our code ran, and conf fsyncs the whole file on each set.

This replaces it with createSettingsStore(file):

  • Reads the file once, rewrites it whole with JSON.stringify(data, null, "\t") via temp file + rename — byte-identical format, so existing profiles and older builds keep working
  • getStore(name) keeps its signature and lazy construction (userData is set after import)
  • An unreadable file is moved to <file>.corrupt and treated as empty instead of failing startup (conf would throw)
  • set(key, undefined) still throws like conf did
  • Unit tests cover round-trip, format, missing file, corrupt file
  • Drops electron-store from package.json (and conf, ajv, ajv-formats, … from the bundle)

Measured with bun run bench:startup (#49758): packaged v2 build, isolated home, warm service, median of 6 launches.

baseline this PR
first main-process log line (app starting) 401 ms 353 ms
renderer process starts 875 ms 829 ms
shell visible 1,325 ms 1,264 ms

Independent of #49770 (skip unchanged background-colour writes), which still avoids a pointless write per launch.

The main process only calls get, set and delete on electron-store, but
importing it pulled conf, ajv, ajv-formats, semver and their trees into
every launch: ~36 ms of CommonJS requires in the startup trace before
any of our code ran, plus an fsync on every write. Read the same
tab-indented JSON file once and rewrite it atomically instead. Existing
profiles and older builds keep working because the file format is
unchanged; an unreadable file is set aside as .corrupt rather than
blocking startup.

Packaged build, warm service, median of 6 launches: first main-process
log line 401 -> 353 ms after spawn.
@Hona
Hona requested a review from Brendonovich as a code owner September 18, 2026 14:27
Copilot AI lite review requested due to automatic review settings September 18, 2026 14:27

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@Hona
Hona merged commit f6353a4 into v2 Sep 18, 2026
10 checks passed
@Hona
Hona deleted the settings-store branch September 18, 2026 23:41
jinhuang712 pushed a commit to jinhuang712/opencode that referenced this pull request Sep 26, 2026
divyanshusingh2903 added a commit to divyanshusingh2903/forge that referenced this pull request Oct 21, 2026
Read and write the same tab-indented JSON file electron-store used, so
existing profiles and older builds are unaffected, without loading
electron-store and its schema validation at startup. An unreadable file is
set aside instead of blocking startup. Ported from upstream f6353a4.

The electron-store dependency is left in package.json so the lockfile is
unchanged. On a dev build the window's first server request moves from
~1.1s to ~1.04s.

Upstream: anomalyco/opencode@f6353a48b5 (anomalyco#49791)
divyanshusingh2903 added a commit to divyanshusingh2903/forge that referenced this pull request Oct 21, 2026
Read and write the same tab-indented JSON file electron-store used, so
existing profiles and older builds are unaffected, without loading
electron-store and its schema validation at startup. An unreadable file is
set aside instead of blocking startup. Ported from upstream f6353a4.

The electron-store dependency is left in package.json so the lockfile is
unchanged. On a dev build the window's first server request moves from
~1.1s to ~1.04s.

Upstream: anomalyco/opencode@f6353a48b5 (anomalyco#49791)
divyanshusingh2903 added a commit to divyanshusingh2903/forge that referenced this pull request Oct 21, 2026
Read and write the same tab-indented JSON file electron-store used, so
existing profiles and older builds are unaffected, without loading
electron-store and its schema validation at startup. An unreadable file is
set aside instead of blocking startup. Ported from upstream f6353a4.

The electron-store dependency is left in package.json so the lockfile is
unchanged. On a dev build the window's first server request moves from
~1.1s to ~1.04s.

Upstream: anomalyco/opencode@f6353a48b5 (anomalyco#49791)
divyanshusingh2903 added a commit to divyanshusingh2903/forge that referenced this pull request Oct 21, 2026
…anomalyco#49791)

Read and write the same tab-indented JSON file electron-store used, so
existing profiles and older builds are unaffected, without loading
electron-store and its schema validation at startup. An unreadable file is
set aside instead of blocking startup. Ported from upstream f6353a4.

The electron-store dependency is left in package.json so the lockfile is
unchanged. On a dev build the window's first server request moves from
~1.1s to ~1.04s.

Upstream: anomalyco/opencode@f6353a48b5 (anomalyco#49791)
divyanshusingh2903 added a commit to divyanshusingh2903/forge that referenced this pull request Oct 21, 2026
…anomalyco#49791)

Read and write the same tab-indented JSON file electron-store used, so
existing profiles and older builds are unaffected, without loading
electron-store and its schema validation at startup. An unreadable file is
set aside instead of blocking startup. Ported from upstream f6353a4.

The electron-store dependency is left in package.json so the lockfile is
unchanged. On a dev build the window's first server request moves from
~1.1s to ~1.04s.

Upstream: anomalyco/opencode@f6353a48b5 (anomalyco#49791)
Co-authored-by: Luke Parker <[email protected]>
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