A light-weight module that brings window.fetch to Node.js
Latest commit 908f661 Jan 14, 2017 @TimothyGu TimothyGu 2.0.0-alpha.1
Fixes #8.
Fixes #209.
Fixes #222.



npm version build status coverage status

A light-weight module that brings window.fetch to Node.js


Instead of implementing XMLHttpRequest in Node.js to run browser-specific Fetch polyfill, why not go from native http to Fetch API directly? Hence node-fetch, minimal code for a window.fetch compatible API on Node.js runtime.

See Matt Andrews' isomorphic-fetch for isomorphic usage (exports node-fetch for server-side, whatwg-fetch for client-side).


  • Stay consistent with window.fetch API.
  • Make conscious trade-off when following whatwg fetch spec and stream spec implementation details, document known difference.
  • Use native promise, but allow substituting it with [insert your favorite promise library].
  • Use native stream for body, on both request and response.
  • Decode content encoding (gzip/deflate) properly, and convert string output (such as res.text() and res.json()) to UTF-8 automatically.
  • Useful extensions such as timeout, redirect limit, response size limit, explicit errors for troubleshooting.

Difference from client-side fetch

  • See Known Differences for details.
  • If you happen to use a missing feature that window.fetch offers, feel free to open an issue.
  • Pull requests are welcomed too!


npm install node-fetch --save


import fetch from 'node-fetch';
// or
// const fetch = require('node-fetch');

// if you are using your own Promise library, set it through fetch.Promise. Eg.

// import Bluebird from 'bluebird';
// fetch.Promise = Bluebird;

// plain text or html

    .then(res => res.text())
    .then(body => console.log(body));

// json

    .then(res => res.json())
    .then(json => console.log(json));

// catching network error
// 3xx-5xx responses are NOT network errors, and should be handled in then()
// you only need one catch() at the end of your promise chain

    .catch(err => console.error(err));

// stream
// the node.js way is to use stream when possible

    .then(res => {
        const dest = fs.createWriteStream('./octocat.png');

// buffer
// if you prefer to cache binary data in full, use buffer()
// note that buffer() is a node-fetch only API

import fileType from 'file-type';

    .then(res => res.buffer())
    .then(buffer => fileType(buffer))
    .then(type => { /* ... */ });

// meta

    .then(res => {

// post

fetch('http://httpbin.org/post', { method: 'POST', body: 'a=1' })
    .then(res => res.json())
    .then(json => console.log(json));

// post with stream from file

import { createReadStream } from 'fs';

const stream = createReadStream('input.txt');
fetch('http://httpbin.org/post', { method: 'POST', body: stream })
    .then(res => res.json())
    .then(json => console.log(json));

// post with JSON

var body = { a: 1 };
fetch('http://httpbin.org/post', { 
    method: 'POST',
    body:    JSON.stringify(body),
    headers: { 'Content-Type': 'application/json' },
    .then(res => res.json())
    .then(json => console.log(json));

// post with form-data (detect multipart)

import FormData from 'form-data';

const form = new FormData();
form.append('a', 1);
fetch('http://httpbin.org/post', { method: 'POST', body: form })
    .then(res => res.json())
    .then(json => console.log(json));

// post with form-data (custom headers)
// note that getHeaders() is non-standard API

import FormData from 'form-data';

const form = new FormData();
form.append('a', 1);
fetch('http://httpbin.org/post', { method: 'POST', body: form, headers: form.getHeaders() })
    .then(res => res.json())
    .then(json => console.log(json));

// node 7+ with async function

(async function () {
    const res = await fetch('https://api.github.com/users/github');
    const json = await res.json();

See test cases for more examples.


fetch(url, options)

Returns a Promise


Should be an absolute url, eg http://example.com/


Note that only method, headers, redirect and body are allowed in window.fetch. Other options are node.js extensions. The default values are shown after each option key.

    method: 'GET'
    , headers: {}        // request header. format {a:'1'} or {b:['1','2','3']}
    , redirect: 'follow' // set to `manual` to extract redirect headers, `error` to reject redirect
    , follow: 20         // maximum redirect count. 0 to not follow redirect
    , timeout: 0         // req/res timeout in ms, it resets on redirect. 0 to disable (OS limit applies)
    , compress: true     // support gzip/deflate content encoding. false to disable
    , size: 0            // maximum response body size in bytes. 0 to disable
    , body: empty        // request body. can be a string, buffer, readable stream
    , agent: null        // http.Agent instance, allows custom proxy, certificate etc.




Thanks to github/fetch for providing a solid implementation reference.