The Fetch API doesn't have a built-in timeout option. You need to use
AbortController combined with setTimeout to implement timeouts.
This is important for user experience — you don't want users waiting indefinitely
for a response that may never come.
Basic Timeout Pattern
async function fetchWithTimeout(url, options = {}, timeoutMs = 5000) {
const controller = new AbortController();
const timeoutId = setTimeout(() => {
controller.abort();
}, timeoutMs);
try {
const response = await fetch(url, {
...options,
signal: controller.signal
});
clearTimeout(timeoutId);
return response;
} catch (error) {
clearTimeout(timeoutId);
if (error.name === 'AbortError') {
throw new Error(`Request timed out after ${timeoutMs}ms`);
}
throw error;
}
}
try {
const response = await fetchWithTimeout('/api/data', {}, 3000);
const data = await response.json();
} catch (error) {
console.error(error.message);
}
The AbortController.signal is passed to fetch. When abort()
is called, the fetch Promise rejects with an AbortError.
Using AbortSignal.timeout() (Modern)
async function fetchWithTimeout(url, options = {}, timeoutMs = 5000) {
try {
const response = await fetch(url, {
...options,
signal: AbortSignal.timeout(timeoutMs)
});
return response;
} catch (error) {
if (error.name === 'TimeoutError') {
throw new Error(`Request timed out after ${timeoutMs}ms`);
}
if (error.name === 'AbortError') {
throw new Error('Request was cancelled');
}
throw error;
}
}
AbortSignal.timeout() is a newer API that handles the timeout automatically.
It throws a TimeoutError instead of AbortError.
Combining Timeout with Manual Abort
function createFetchController(timeoutMs = 5000) {
const controller = new AbortController();
const timeoutSignal = AbortSignal.timeout(timeoutMs);
const combinedSignal = AbortSignal.any([
controller.signal,
timeoutSignal
]);
return {
signal: combinedSignal,
abort: () => controller.abort()
};
}
const { signal, abort } = createFetchController(5000);
window.addEventListener('beforeunload', abort);
const response = await fetch('/api/data', { signal });
← Back to HTTP Examples