#17409 · @BYK · opened Mar 13, 2026 at 6:44 PM UTC · last updated Mar 21, 2026 at 10:24 AM UTC

fix(opencode): limit concurrent bootstraps, async filesystem I/O, bounded dir walk

appfix
71
+33197 files

Score breakdown

Impact

9.0

Clarity

9.0

Urgency

9.0

Ease Of Review

9.0

Guidelines

8.0

Readiness

8.0

Size

8.0

Trust

5.0

Traction

2.0

Summary

This PR addresses severe server performance degradation when many projects load concurrently by limiting bootstrap concurrency, converting sync filesystem calls to async, and bounding directory walk depth. It significantly improves server responsiveness and prevents health check timeouts for users with many sidebar projects. This is a critical performance fix.

Open in GitHub

Description

Issue for this PR

Closes #17407

Type of change

  • [x] Bug fix
  • [ ] New feature
  • [x] Refactor / code improvement
  • [ ] Documentation

What does this PR do?

Three changes to reduce server event loop contention when many projects load concurrently (e.g. opening ~/Code with 17 sidebar projects):

1. Instance bootstrap concurrency limit (p-limit, N=3): Each Instance bootstrap spawns 5-7 subprocesses (git, ripgrep, parcel/watcher). With 17 concurrent bootstraps that's ~100 subprocesses overwhelming a 4-core SATA SSD system. The p-limit semaphore gates new directory bootstraps while allowing cache-hit requests through instantly. Peak subprocesses: ~100 → ~18.

2. Async Filesystem.exists and isDir: Filesystem.exists() wrapped existsSync() in an async function — it looked async but blocked the event loop on every call. Replaced with fs.promises.access(). Same for isDir (statSyncfs.promises.stat). This lets the event loop serve health checks and API responses while directory walk-ups are in progress. Added Filesystem.existsSync() for callers that genuinely need sync behavior.

3. Bounded Filesystem.up/findUp walk depth (maxDepth=10): Previously walked all the way to / with no limit. Added maxDepth parameter (default 10) as a safety net against degenerate deep paths.

How did you verify your code works?

  • Tested with 17 sidebar projects — server stays responsive during bootstrap
  • Health checks no longer timeout during concurrent bootstraps
  • All existing tests pass

Screenshots / recordings

N/A — backend changes only.

Checklist

  • [x] I have tested my changes locally
  • [x] I have not included unrelated changes in this PR

Linked Issues

#17407 Server overwhelmed by concurrent project bootstraps when many sidebar projects exist

View issue

Comments

No comments.

Changed Files

bun.lock

+41
@@ -369,6 +369,7 @@
"open": "10.1.2",
"opencode-gitlab-auth": "2.0.0",
"opentui-spinner": "0.0.6",
"p-limit": "7.3.0",
"partial-json": "0.1.7",
"remeda": "catalog:",
"semver": "^7.6.3",
@@ -3804,7 +3805,7 @@
"p-finally": ["p-finally@1.0.0", "", {}, "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow=="],
"p-limit": ["p-limit@6.2.0", "", { "dependencies": { "yocto-queue": "^1.1.1" } }, "sha512-kuUqqHNUqoIWp/c467RI4X6mmyuojY5jGutNU0wVTmEOOfcuwLqyMVoAi9MKi2Ak+5i9+nhmrK4ufZE8069kHA=="],
"p-limit": ["p-limit@7.3.0", "", { "dependencies": { "yocto-queue": "^1.2.1" } }, "sha512-7cIXg/Z0M5WZRblrsOla88S4wAK+zOQQWeBYfV3qJuJXMr+LnbYjaadrFaS0JILfEDPVqHyKnZ1Z/1d6J9VVUw=="],
"p-locate": ["p-locate@4.1.0", "", { "dependencies": { "p-limit": "^2.2.0" } }, "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A=="],
@@ -5334,6 +5335,8 @@
"astro/diff": ["diff@5.2.2", "", {}, "sha512-vtcDfH3TOjP8UekytvnHH1o1P4FcUdt4eQ1Y+Abap1tk/OB2MWQvcwS2ClCd1zuIhc3JKOx6p3kod8Vfys3E+A=="],
"astro/p-limit": ["p-limit@6.2.0", "", { "d

packages/app/src/components/dialog-connect-provider.tsx

+11
@@ -383,7 +383,7 @@ export function DialogConnectProvider(props: { provider: string }) {
setFormStore("error", undefined)
await globalSDK.client.auth.set({
providerID: props.provider,
auth: {
body: {
type: "api",
key: apiKey,
},

packages/app/src/components/dialog-custom-provider.tsx

+11
@@ -131,7 +131,7 @@ export function DialogCustomProvider(props: Props) {
const auth = result.key
? globalSDK.client.auth.set({
providerID: result.providerID,
auth: {
body: {
type: "api",
key: result.key,
},

packages/opencode/package.json

+10
@@ -134,6 +134,7 @@
"open": "10.1.2",
"opencode-gitlab-auth": "2.0.0",
"opentui-spinner": "0.0.6",
"p-limit": "7.3.0",
"partial-json": "0.1.7",
"remeda": "catalog:",
"semver": "^7.6.3",

packages/opencode/src/cli/cmd/tui/component/dialog-provider.tsx

+11
@@ -265,7 +265,7 @@ function ApiMethod(props: ApiMethodProps) {
if (!value) return
await sdk.client.auth.set({
providerID: props.providerID,
auth: {
body: {
type: "api",
key: value,
},

packages/opencode/src/project/instance.ts

+61
@@ -6,6 +6,7 @@ import { Log } from "@/util/log"
import { Context } from "../util/context"
import { Project } from "./project"
import { State } from "./state"
import pLimit from "p-limit"
export interface Shape {
directory: string
@@ -19,6 +20,10 @@ const disposal = {
all: undefined as Promise<void> | undefined,
}
// Limit concurrent Instance bootstraps to avoid overwhelming the system
// with subprocesses (each bootstrap spawns 5-7 git/ripgrep processes).
const limit = pLimit(3)
function emit(directory: string) {
GlobalBus.emit("event", {
directory,
@@ -32,7 +37,7 @@ function emit(directory: string) {
}
function boot(input: { directory: string; init?: () => Promise<any>; project?: Project.Info; worktree?: string }) {
return iife(async () => {
return limit(async () => {
const ctx =
input.project && input.worktree
? {

packages/opencode/src/util/filesystem.ts

+1914
@@ -1,5 +1,5 @@
import { chmod, mkdir, readFile, writeFile } from "fs/promises"
import { createWriteStream, existsSync, statSync } from "fs"
import { chmod, mkdir, readFile, writeFile, access, stat as fsStat } from "fs/promises"
import { createWriteStream, existsSync as nodeExistsSync, statSync } from "fs"
import { lookup } from "mime-types"
import { realpathSync } from "fs"
import { dirname, join, relative, resolve as pathResolve } from "path"
@@ -8,17 +8,22 @@ import { pipeline } from "stream/promises"
import { Glob } from "./glob"
export namespace Filesystem {
// Fast sync version for metadata checks
export async function exists(p: string): Promise<boolean> {
return existsSync(p)
return access(p).then(
() => true,
() => false,
)
}
export function existsSync(p: string): boolean {
return nodeExistsSync(p)
}
export async function isDir(p: string): Promise<boolean> {
try {
return statSync(p).isDirectory()
} catch {
return false
}
return fsStat(p).then(
(s) => s.isDirectory(),
() => false,
)
}
export function stat(p: string): ReturnType<typeof statSync> | un