What RequestInit is
The second argument to fetch(input, init) is a RequestInit dictionary. Every
field is optional, and the defaults are tuned for the common case of a simple
same-page GET. Knowing the defaults matters: many subtle bugs — a cookie that
never sends, a cross-origin response you cannot read, a stale cached body — come
down to an option left at its default when you needed to override it.
How it works
When you call fetch, the browser merges your init object with the defaults to
build a Request. The fields fall into a few groups: request line (method,
body), headers (headers), security and network policy (mode,
credentials, referrerPolicy, redirect), caching (cache), lifecycle
(signal, keepalive, priority), and integrity (integrity). The reference
below lists each field with its type, default, and the gotcha most likely to bite
you, plus a builder that assembles a real init object from your selections.
Tips and notes
Three defaults trip people up most often: mode is cors so cross-origin reads
need server CORS headers; credentials is same-origin so cookies do not
ride along cross-origin unless you set include; and redirect is follow so a
30x is transparently chased. Use cache: 'no-store' to truly bypass the HTTP
cache, an AbortController signal to cancel, and keepalive for beacons sent
during page unload.
Complete RequestInit field reference
| Field | Type | Default | Key behaviour |
|---|---|---|---|
method | string | 'GET' | Case-insensitive; GET and HEAD bodies are ignored |
headers | Headers or plain object | {} | Forbidden headers (e.g. Host, Cookie) are silently dropped by the browser |
body | string, Blob, FormData, ReadableStream, etc. | null | Cannot be used with GET or HEAD |
mode | 'cors', 'same-origin', 'no-cors', 'navigate' | 'cors' | no-cors gives an opaque response; you cannot read its body |
credentials | 'omit', 'same-origin', 'include' | 'same-origin' | Must be 'include' with Access-Control-Allow-Credentials: true for cross-origin cookies |
cache | 'default', 'no-store', 'reload', 'no-cache', 'force-cache', 'only-if-cached' | 'default' | no-cache revalidates; no-store bypasses entirely |
redirect | 'follow', 'error', 'manual' | 'follow' | 'error' throws on redirect; 'manual' gives an opaque redirect response |
referrerPolicy | standard Referrer-Policy tokens | '' (browser default) | Controls Referer header sent with the request |
integrity | string | '' | Subresource Integrity hash, e.g. 'sha384-...' |
keepalive | boolean | false | Allows request to outlive the page; 64 KB body cap |
signal | AbortSignal | null | Pass AbortController.signal to cancel |
priority | 'high', 'low', 'auto' | 'auto' | Hints to the browser’s fetch prioritization |
Aborting a fetch
The signal option accepts an AbortSignal. Create an AbortController, pass its .signal, and call .abort() to cancel:
const controller = new AbortController();
fetch('/api/data', { signal: controller.signal })
.then(r => r.json())
.catch(err => {
if (err.name === 'AbortError') {
console.log('Request was cancelled');
}
});
// Cancel after 5 seconds
setTimeout(() => controller.abort(), 5000);
One AbortController can cancel multiple in-flight requests simultaneously if the same .signal is passed to each.
The cache option in depth
'default'— follows normal HTTP cache semantics (checksCache-Control,ETag,Last-Modified).'no-cache'— always validates with the server (sendsIf-None-Match/If-Modified-Since); uses the cached copy if the server responds with 304.'no-store'— never reads from or writes to the cache. Forces a fresh network request every time.'reload'— fetches from the network and updates the cache, but does not send conditional headers.'force-cache'— uses the cached copy regardless of freshness; only hits the network if there is no cached entry.'only-if-cached'— returns cached copy or throws a network error if not cached. Only works withmode: 'same-origin'.