Fixing Timeout Behavior in GrowthBook JS SDK refreshFeatures()

The GrowthBook JavaScript SDK was not persisting the timeout option from init() to later refreshFeatures() calls, causing network requests to hang indefinitely on slow connections. This fix ensures the initialization timeout is reused as a sensible default across all refresh operations.
What
When you pass a timeout to GrowthBook's init() method, it was only applied to the first automatic feature refresh and then discarded. Any manual call to refreshFeatures() without an explicit timeout would run with no timeout at all, potentially blocking forever if the network was slow or unreachable. The fix stores the init timeout in a private field and applies it as a fallback in the refresh logic, matching how disableCache and backgroundSync already work.
Why it matters
Timeouts are a critical safety mechanism for network operations. Without them, a single slow API call can freeze your entire application. The inconsistency meant developers had to manually pass timeouts to every refreshFeatures() call or risk hangs, defeating the purpose of setting a sensible default at initialization time.
Who it's for
Any developer using the GrowthBook JavaScript SDK (browser or Node.js) who relies on feature flag updates after initialization. This is especially important for applications running in resource-constrained environments or behind unreliable networks.
When & where
This fix is up as pull request #6158 against the main growthbook/growthbook repository, marked ready for review and waiting on a maintainer. It has passed the full jest test suite (677 tests across 15 suites) and includes a new regression test that confirms the hang behavior on the old code and validates the timeout behavior on the fixed version.
How
The solution adds a private _initTimeout field to both GrowthBook and GrowthBookClient classes to store the timeout from init options. The internal refresh method then uses a nullish coalescing operator (timeout ?? this._initTimeout) so explicit per-call timeouts still take priority while falling back to the stored init default. No new dependencies were added, keeping the SDK's zero-dependency promise intact.
Takeaway
Small but important: persisting configuration defaults across method calls prevents subtle hangs and makes APIs more predictable. This fix aligns the timeout behavior with other options that already follow this pattern, reducing cognitive load for developers and making the SDK safer by default.
Pull request (ready for review): https://github.com/growthbook/growthbook/pull/6158
Building an AI agent?
I'm packaging how I ship them into one kit. Early access:
AI Agent Starter Kit →