
Building App-Wide Search: How Debounce Cut Our API Calls by 50%
Intermediate · 7 min read · 2026-09-11
Search-as-you-type is a really cool feature until we found that every keystroke is trigerring off its own API call.
The problem
Initially, every keystroke triggered its own API call:
const handleSearch = (event) => {
const { value } = event.target;
handleSearchRequest(value);
};
Type "contact" and it just sends 7 requests, most of which are obsolete before the response even comes back.
The fix
Wrapped the request in a debounce, so it only fires once the user actually pauses typing:
const debounce = (func, delay) => {
let timeoutId;
return (...args) => {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => func(...args), delay);
};
};
const debouncedSendRequest = debounce(handleSearchRequest, 250);
const handleSearch = (event) => {
const { value } = event.target;
debouncedSendRequest(value);
};
Now every keystroke resets the same timer instead of starting a new one. Only the last keystroke actually triggers a fetch.
The result
With debouncing, redundant API calls dropped by roughly 50% resulting in a lighter load on the backend, and a search experience that still felt responsive to the user.
