Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Use Node.js’s built-in, browser-compatible fetch() for most HTTP requests. Await the returned Response, check response.ok (or the status code), then read the body with the method that matches its format. Unlike many request libraries, fetch() does not reject merely because a server returns 404 or 500.

This guide covers runtime versions, GET and JSON POST requests, headers, authentication, parsing, timeouts, cancellation, redirects, retries, streaming, troubleshooting, and when the lower-level Undici or node:http APIs are a better fit.

Is fetch built into Node.js?

Yes, on current Node.js releases. Node added the global Fetch API in v17.5.0 and v16.15.0. The experimental flag was no longer required in v18.0.0, and Fetch was no longer experimental in v21.0.0. Node’s implementation is based on Undici and also exposes related web-style globals such as Headers, Request, Response, and FormData.

Check the runtime used by your application, not just the version installed on your workstation:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
#1 Best Overall
Elebase USB to USB C Adapter for iPhone 18 Pro Max,USBC Car Charger Adapter
  • Read Before You Buy — No Video Output: These adapters support charging and USB 2.0 data transfer, but cannot transmit video signals. Except for standard USB webcams (which use USB data only), they are not compatible with HDMI/DisplayPort cables, video-capable USB-C hubs, or docking stations with video output.
  • Convert USB-A Ports to USB-C: Designed to connect USB-C earphones, cables, flash drives, card readers, and other USB-C accessories to standard USB-A ports. Plug-and-play with no drivers or software required.
  • Aluminum Alloy Housing: Built with a sturdy aluminum alloy shell that aids in heat dissipation and protects against daily wear and scratches. Designed to maintain a stable and secure connection.
  • Compact & Travel-Friendly: The ultra-compact design allows the adapter to stay plugged into your device without blocking adjacent ports or adding bulk, reducing wear and tear on your original USB ports.
  • 12-Month Warranty: Backed by a 12-month manufacturer warranty for peace of mind. Designed to meet strict quality control standards for reliable everyday performance.
node --version

If you support an older release without global Fetch, upgrade Node or deliberately add a compatible HTTP client rather than assuming the global exists.

The basic request pattern

fetch(input, init) accepts a URL string, a URL object, or a Request. The optional init object controls the method, headers, body, redirect mode, and abort signal.

const response = await fetch('https://api.example.com/data');

if (!response.ok) {
  throw new Error(`HTTP ${response.status} ${response.statusText}`);
}

const data = await response.json();
console.log(data);

The promise fulfills when response headers are available. The body is read separately, and each response body can normally be consumed only once.

Why a 404 does not enter catch automatically

Fetch rejects its promise for network-level failures, such as DNS errors, connection failures, or an aborted request. An HTTP error status such as 404 still fulfills the promise. Always test response.ok, which is true only for status codes from 200 through 299, before treating the result as successful.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
try {
  const response = await fetch(url);

  if (!response.ok) {
    const detail = await response.text();
    throw new Error(`Request failed (${response.status}): ${detail}`);
  }

  return await response.json();
} catch (error) {
  console.error('Network, cancellation, or application error:', error);
}

GET requests and response bodies

A GET is the default, so no method option is needed. Select one body reader and use it deliberately:

  • response.json() for valid JSON.
  • response.text() for text, HTML, CSV, or diagnostic error messages.
  • response.arrayBuffer() for binary data.
  • response.blob() where Blob handling is useful.
  • response.formData() for compatible form-data responses.
const response = await fetch('https://api.example.com/report');
console.log(response.status, response.statusText);
console.log('content type:', response.headers.get('content-type'));

if (!response.ok) {
  throw new Error(await response.text());
}

const report = await response.json();

Calling two body methods on the same response fails because the stream has already been consumed. If two independent consumers need the body, call response.clone() before reading either copy.

Rank #2
Anker USB-C Hub, 5-in-1 USB Hub for Laptops, 4K HDMI Multiport Adapter
  • 5-in-1 USB-C Hub: Experience comprehensive connectivity featuring a Power Delivery input, two USB-A 2.0 ports, a USB-A 3.0 port, and an HDMI port. (Note: The USB-C power delivery input port is only for connecting an external wall charger to power your laptop and cannot power peripheral devices.)
  • 90W Pass-Through Charging: Achieve optimal charging with 90W pass-through power to your laptop, supported by a total input of 100W, with the hub reserving 10W for operational efficiency. (Note: Wall charger not included.)
  • Quick Data Transfers: Accelerate your productivity with rapid data transfers using a high-speed 5Gbps USB 3.0 port and two 480Mbps USB 2.0 ports.
  • 4K HDMI Display: Enhance your visual experience with a hub capable of delivering 4K resolution at 30Hz in both mirror and extend modes. Please note that this hub is compatible with MacBook (macOS 12 and newer), Windows 10 and 11, ChromeOS, and laptops equipped with DP Alt Mode and Power Delivery. Note: This device is not compatible with Linux.
  • What You Get: Anker USB-C Hub (5-in-1, 4K HDMI), welcome guide, 18-month warranty, and our friendly customer service.

Sending JSON with POST, PUT, or PATCH

Serialize the JavaScript value and set the content type explicitly. The server may require additional headers such as an authorization token or an idempotency key.

const payload = { name: 'example', enabled: true };

const response = await fetch('https://api.example.com/items', {
  method: 'POST',
  headers: {
    'content-type': 'application/json',
    'accept': 'application/json',
    'authorization': `Bearer ${process.env.API_TOKEN}`,
  },
  body: JSON.stringify(payload),
});

if (!response.ok) {
  const message = await response.text();
  throw new Error(`Create failed (${response.status}): ${message}`);
}

const created = await response.json();
console.log(created);

Use PUT for an API’s replacement semantics and PATCH for partial updates; the server, not Fetch, defines those semantics. Do not send a JavaScript object directly as the body: convert it with JSON.stringify.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Headers, query parameters, and authentication

Constructing query strings safely

Use URL and URLSearchParams instead of concatenating unescaped values:

const endpoint = new URL('https://api.example.com/search');
endpoint.searchParams.set('q', 'node fetch');
endpoint.searchParams.set('limit', '20');

const response = await fetch(endpoint, {
  headers: { accept: 'application/json' },
});

Header rules

Header names are case-insensitive. Keep secrets in environment variables, never in source control or URLs. Send an Authorization header only to the intended origin, and avoid logging its value. The Headers class can validate and manipulate headers when you need a reusable collection.

Timeouts and cancellation

Fetch has no implicit application deadline. Pass an AbortSignal; Node provides AbortSignal.timeout(delay) for a fixed limit:

const response = await fetch(url, {
  signal: AbortSignal.timeout(5_000),
});

An AbortController is useful when cancellation is driven by application logic:

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Rank #3
Sale
Anker USB C Hub, 7in1 Multi-Port USB Adapter, 4K@60Hz USBC to HDMI Splitter
  • Sleek 7-in-1 USB-C Hub: Features an HDMI port, two USB-A 3.0 ports, and a USB-C data port, each providing 5Gbps transfer speeds. It also includes a USB-C PD input port for charging up to 100W and dual SD and TF card slots, all in a compact design.
  • Flawless 4K@60Hz Video with HDMI: Delivers exceptional clarity and smoothness with its 4K@60Hz HDMI port, making it ideal for high-definition presentations and entertainment. (Note: Only the HDMI port supports video projection; the USB-C port is for data transfer only.)
  • Double Up on Efficiency: The two USB-A 3.0 ports and a USB-C port support a fast 5Gbps data rate, significantly boosting your transfer speeds and improving productivity.
  • Fast and Reliable 85W Charging: Offers high-capacity, speedy charging for laptops up to 85W, so you spend less time tethered to an outlet and more time being productive.
  • What You Get: Anker USB-C Hub (7-in-1), welcome guide, 18-month warranty, and our friendly customer service.
const controller = new AbortController();
const timer = setTimeout(() => controller.abort(), 5_000);

try {
  const response = await fetch(url, { signal: controller.signal });
  if (!response.ok) throw new Error(`HTTP ${response.status}`);
  return await response.json();
} finally {
  clearTimeout(timer);
}

An aborted request rejects. Distinguish that case from an HTTP response so callers can decide whether to retry or report cancellation.

Redirects and security decisions

Fetch supports redirect modes: follow (the usual default), error, and manual. Choose explicitly when redirects could change the destination, credentials, or API semantics.

const response = await fetch(url, {
  redirect: 'error',
});

Do not blindly forward authorization headers to a redirected host. Validate redirect targets when an API’s security model requires it.

Retries without making failures worse

Fetch does not retry automatically. Retry only operations that are safe to repeat, or use an API-provided idempotency key for writes. Limit attempts, add backoff, and stop on permanent client errors such as most 400-series responses.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
async function getWithRetry(url, attempts = 3) {
  for (let attempt = 1; attempt <= attempts; attempt++) {
    try {
      const response = await fetch(url, {
        signal: AbortSignal.timeout(10_000),
      });
      if (response.ok) return response;
      if (response.status >= 400 && response.status < 500 && response.status !== 429) {
        throw new Error(`Permanent HTTP error ${response.status}`);
      }
      if (attempt === attempts) throw new Error(`HTTP ${response.status}`);
    } catch (error) {
      if (attempt === attempts) throw error;
    }
    await new Promise(resolve => setTimeout(resolve, 2 ** attempt * 250));
  }
}

For production clients, honor a server’s Retry-After guidance and add jitter so many workers do not retry simultaneously.

Streaming and large responses

For ordinary JSON, response.json() is simplest. Large downloads should be processed incrementally rather than accumulated in memory. Node’s Fetch response exposes a Web Streams body; use the stream APIs appropriate to your Node version and consume or cancel it deliberately. Leaving bodies unread can reduce connection reuse and throughput.

Rank #4
Sale
UGREEN USB to USB C Adapter Combo 4-Pack, 10Gbps USB C Converter Space Gray
  • Dual Converters, Infinite Potential:Includes 2× USB C male to USB A female adapters and 2× USB A male to USB C female adapters. Perfect for a wide range of uses—tablets with Bluetooth keyboards, expand USB ports on macbook, and more. Two different converters for all your daily needs
  • Next-Level 10Gbps & 3A Charging: No more slow 480Mbps, this usb to usb c adapter has a transfer speed of up to 10Gbps, allowing you to do more transferring in less time. This usb adapter fits both USB A and USB C charger, supporting up to 3A fast charging
  • Upgraded Exquisite Craftsmanship: With an aluminum alloy housing and metal connector, the usbc to usb adapter is extremely durable and sturdy. Rigorously tested to withstand more than 10,000 times of plugging and unplugging, ensuring long-lasting performance
  • Broad Compatible: The usb c to usb adapter widely supports all USB C/ USB A devices like laptops, tablets, cellphones, car chargers, and phone chargers. Such as compatible with MacBook Pro/Air 2023/2022, Thunderbolt 4/3 Devices,Apple MagSafe Watch 9/8/7/SE/Ultra, iPad Pro 2022/2021, Samsung Galaxy S23/S20/S10, and iPhone 17/16/15 Pro. Plug and play
  • Please Note: To reach 10Gbps speed, keep the cable under 3.3 ft. For USB A Male to USB C adapters, try flipping the USB C connector. USB C Male to USB A adapters support bidirectional 10Gbps transfer within 3.3 ft

Custom transport with Undici

Node’s Fetch layer accepts an Undici-compatible dispatcher when you need connection-level behavior:

import { Agent } from 'undici';

const response = await fetch(url, {
  dispatcher: new Agent({
    connect: { rejectUnauthorized: false },
  }),
});

Disabling TLS certificate verification is an exceptional, controlled configuration for a trusted test environment, not a general workaround. Undici’s setGlobalDispatcher() can change the dispatcher globally, so scope that decision carefully in shared applications.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Fetch, Undici clients, or node:http?

Approach Abstraction and body model Error and cancellation model Use it when
Global fetch() Web-compatible Request/Response and body readers or Web Streams Inspect HTTP status; AbortSignal cancels Most API calls and service integrations
Undici lower-level clients More direct status and streamed-body control Deliberate body consumption and transport configuration You need pooling, dispatchers, or performance-oriented controls beyond Fetch
node:http Low-level Node request and socket lifecycle APIs Request events, streams, and explicit lifecycle handling You require controls that the Fetch abstraction does not expose

Start with Fetch. Move down a layer for a demonstrated transport or lifecycle requirement, not because a 404 needs special library behavior.

Complete runnable examples

Node.js

const url = 'https://api.example.com/items';

async function main() {
  const response = await fetch(url, {
    method: 'POST',
    headers: {
      'content-type': 'application/json',
      accept: 'application/json',
    },
    body: JSON.stringify({ name: 'example' }),
    signal: AbortSignal.timeout(15_000),
  });

  if (!response.ok) {
    throw new Error(`HTTP ${response.status}: ${await response.text()}`);
  }

  console.log(await response.json());
}

main().catch(error => {
  console.error(error);
  process.exitCode = 1;
});

cURL equivalent

curl -X POST https://api.example.com/items 
  -H 'content-type: application/json' 
  -H 'accept: application/json' 
  -d '{"name":"example"}'

Python equivalent

import requests

r = requests.post(
    'https://api.example.com/items',
    headers={'accept': 'application/json'},
    json={'name': 'example'},
    timeout=15,
)
r.raise_for_status()
print(r.json())
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Or skip the browser setup

If your Node application’s goal is to obtain website screenshots rather than call an arbitrary JSON API, ScreenshotNeo provides a single HTTP endpoint. It accepts consent banners like a visitor, removes more than 60 known consent platforms plus newsletter popups and chat widgets before capture, and reports whether a result was billed. Bot checks, CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed.

Call it from Node with Fetch:

const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const bytes = await res.arrayBuffer();
await Bun.write('shot.webp', bytes);

In standard Node.js, write the bytes with a file handle:

import { writeFile } from 'node:fs/promises';

const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
await writeFile('shot.webp', Buffer.from(await res.arrayBuffer()));

See the ScreenshotNeo documentation for output and options. It also offers an MCP server with take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients. The Free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Troubleshooting common failures

“fetch is not defined”

Your Node runtime predates the built-in global or your execution environment differs from the one you checked. Verify node --version in the deployed process and upgrade to a release with stable Fetch support.

Best Value
Anker USB C Hub, 5-in-1 USBC to HDMI Splitter with 4K Display
  • 5-in-1 Connectivity: Equipped with a 4K HDMI port, a 5 Gbps USB-C data port, two 5 Gbps USB-A ports, and a USB C 100W PD-IN port. Note: The USB C 100W PD-IN port supports only charging and does not support data transfer devices such as headphones or speakers.
  • Powerful Pass-Through Charging: Supports up to 85W pass-through charging so you can power up your laptop while you use the hub. Note: Pass-through charging requires a charger (not included). Note: To achieve full power for iPad, we recommend using a 45W wall charger.
  • Transfer Files in Seconds: Move files to and from your laptop at speeds of up to 5 Gbps via the USB-C and USB-A data ports. Note: The USB C 5Gbps Data port does not support video output.
  • HD Display: Connect to the HDMI port to stream or mirror content to an external monitor in resolutions of up to 4K@30Hz. Note: The USB-C ports do not support video output.
  • What You Get: Anker 332 USB-C Hub (5-in-1), welcome guide, our worry-free 18-month warranty, and friendly customer service.

The code reaches catch for a timeout

An abort is a rejected promise, unlike a 404. Catch the error, identify cancellation where appropriate, and decide whether the operation is safe to retry.

A 404 or 500 appears successful

The promise fulfilled as designed. Check response.ok before reading a success body, and log the status and a bounded error body for diagnosis.

JSON parsing fails

The endpoint may have returned HTML, an empty body, or malformed JSON. Inspect content-type and read response.text() once to see the actual payload.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The server says the body is empty or malformed

Confirm that you used JSON.stringify, set content-type: application/json, and sent the fields the API requires.

Requests hang indefinitely

Add AbortSignal.timeout() or an AbortController. Also check DNS, proxy, firewall, TLS, and server-side latency rather than treating every delay as a Fetch bug.

Connections or memory grow under load

Consume or cancel every response body, avoid loading large payloads with json() when streaming is appropriate, and consider an Undici dispatcher or lower-level client for explicit pooling controls.

Practical checklist

  • Confirm the deployed Node version supports global Fetch.
  • Check response.ok or status for every request.
  • Choose exactly one appropriate body reader.
  • Set JSON content type and serialize JSON bodies.
  • Keep credentials out of source code, logs, and unsafe redirects.
  • Set a deadline with an abort signal.
  • Retry only safe or idempotent operations, with bounded backoff.
  • Use Undici or node:http when you genuinely need lower-level transport control.

Frequently Asked Questions

Can I use fetch in a CommonJS Node.js file?

Yes. On Node releases with global Fetch, call fetch() directly from CommonJS; no import is required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

How can I inspect a response without consuming its body?

Read status and headers first. If two consumers need the payload, call response.clone() before either body reader.

Does fetch automatically send cookies like a browser?

No browser session behavior should be assumed in a Node process. Supply authentication or cookie headers explicitly when the API permits it.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.