cross-fetch vs isomorphic-fetch vs node-fetch
Isomorphic Fetching Strategies in JavaScript
cross-fetchisomorphic-fetchnode-fetchSimilar Packages:

Isomorphic Fetching Strategies in JavaScript

cross-fetch, isomorphic-fetch, and node-fetch are libraries designed to bring the fetch API to environments where it is not natively available, primarily Node.js. node-fetch is a lightweight implementation focused specifically on Node.js environments. isomorphic-fetch was an early attempt to provide a universal fetch polyfill for both Node and browsers but is now considered legacy. cross-fetch serves as the modern successor to isomorphic-fetch, offering a true polyfill that works across Node.js, browsers, and React Native without requiring environment checks.

Npm Package Weekly Downloads Trend

3 Years

Github Stars Ranking

Stat Detail

Package
Downloads
Stars
Size
Issues
Publish
License
cross-fetch21,667,7411,69493.3 kB272 years agoMIT
isomorphic-fetch6,455,6996,902-576 years agoMIT
node-fetch08,847107 kB2493 years agoMIT

Cross-Fetch vs Isomorphic-Fetch vs Node-Fetch: Architecture and Maintenance Compared

When building JavaScript applications that run on both the server and the client, handling HTTP requests consistently is critical. cross-fetch, isomorphic-fetch, and node-fetch all aim to solve this, but they differ significantly in maintenance status, module support, and implementation strategy. Let's break down the technical realities to help you make the right choice.

πŸ›‘ Maintenance Status: Active vs Deprecated

The most critical factor is whether the library is still safe to use. isomorphic-fetch is officially deprecated, while cross-fetch and node-fetch remain active.

cross-fetch is actively maintained and serves as the recommended replacement for isomorphic-fetch. It receives regular updates to match the WhatWG fetch standard.

// cross-fetch: Actively maintained
import fetch from 'cross-fetch';
const res = await fetch('https://api.example.com');

isomorphic-fetch is deprecated. The repository and npm page advise users to switch to cross-fetch. Using it introduces technical debt and potential security risks due to lack of patches.

// isomorphic-fetch: Deprecated β€” Do not use in new projects
import 'isomorphic-fetch';
const res = await fetch('https://api.example.com');

node-fetch is actively maintained but focuses solely on Node.js. It is stable but requires version management due to breaking changes between v2 and v3.

// node-fetch: Active (Node.js only)
import fetch from 'node-fetch';
const res = await fetch('https://api.example.com');

πŸ“¦ Module Systems: ESM vs CommonJS

Module compatibility is a major architectural decision, especially for node-fetch. cross-fetch and isomorphic-fetch generally handle both, but node-fetch v3 dropped CommonJS support.

cross-fetch supports both ESM and CommonJS without configuration headaches. You can import it normally in most setups.

// cross-fetch: Works in ESM and CommonJS
import fetch from 'cross-fetch';
// or
const fetch = require('cross-fetch');

isomorphic-fetch was built during the CommonJS era. While it works in legacy setups, it lacks modern ESM optimizations and tree-shaking support.

// isomorphic-fetch: Legacy CommonJS focus
import 'isomorphic-fetch';
// or
require('isomorphic-fetch');

node-fetch requires careful version selection. Version 2 supports CommonJS, but Version 3 is ESM only, which breaks many existing Node.js projects without type: module in package.json.

// node-fetch v2: CommonJS supported
const fetch = require('node-fetch');

// node-fetch v3: ESM only (requires package.json "type": "module")
import fetch from 'node-fetch';

🌍 Polyfill Behavior: Global vs Local Import

How the library injects the fetch API matters for code cleanliness. Some packages modify the global scope, while others require explicit imports.

cross-fetch offers flexibility. You can import it as a function or use it as a polyfill to patch the global scope once.

// cross-fetch: Polyfill mode
import 'cross-fetch/polyfill';
// Now fetch() is available globally
const res = await fetch('https://api.example.com');

isomorphic-fetch works primarily as a side-effect import that patches the global scope. This can lead to hidden dependencies in large codebases.

// isomorphic-fetch: Global patching
import 'isomorphic-fetch';
// fetch() becomes available globally
const res = await fetch('https://api.example.com');

node-fetch does not patch the global scope by default. You must import and use the function explicitly, which is safer for server-side code.

// node-fetch: Explicit import only
import fetch from 'node-fetch';
// No global pollution
const res = await fetch('https://api.example.com');

πŸ› οΈ API Consistency: WhatWG Standards

All three libraries aim to implement the WhatWG fetch standard, but deviations exist in error handling and response types.

cross-fetch strives for strict adherence to the browser's native fetch API. This ensures code written for the browser works identically on the server.

// cross-fetch: Matches browser behavior
const res = await fetch('/api');
if (!res.ok) throw new Error('Request failed');

isomorphic-fetch attempted this but lacks updates for newer standard features like Request or Response constructors in some environments.

// isomorphic-fetch: Older standard implementation
const res = await fetch('/api');
// May lack newer API features

node-fetch closely mirrors the API but has slight differences in error handling. For example, network errors might reject the promise differently than in browsers.

// node-fetch: Node-specific behavior
const res = await fetch('/api');
// Network errors might need specific handling compared to browsers

πŸ“Š Summary: Key Differences

Featurecross-fetchisomorphic-fetchnode-fetch
Statusβœ… Active❌ Deprecatedβœ… Active
Environment🌐 Node, Browser, React Native🌐 Node, Browser (Legacy)πŸ–₯️ Node.js Only
Module System⚑ ESM & CommonJSπŸ•°οΈ CommonJS Focused⚠️ v3 ESM Only, v2 CommonJS
PolyfillπŸ”§ Optional Global PatchπŸ”§ Global Patch❌ Explicit Import Only
RecommendationπŸ† Best for Universal Apps🚫 Do Not UseπŸ† Best for Node-Only Backends

πŸ’‘ The Big Picture

cross-fetch is the standard choice for universal JavaScript applications. It removes the need to write environment-specific code and is the direct successor to isomorphic-fetch. Use this for monorepos, Next.js projects, or libraries meant to run anywhere.

isomorphic-fetch should be avoided in all new development. It is legacy software that no longer receives updates. If you see this in a codebase, plan a migration to cross-fetch.

node-fetch remains the top choice for backend-only services. It is lightweight and optimized for Node.js. Just ensure you pick the right version for your module system β€” v2 for CommonJS, v3 for ESM.

Final Thought: For most modern frontend architects, cross-fetch provides the safest path forward for shared code. Reserve node-fetch for pure server-side utilities where browser compatibility is irrelevant.

How to Choose: cross-fetch vs isomorphic-fetch vs node-fetch

  • cross-fetch:

    Choose cross-fetch for new projects requiring universal support across Node.js, browsers, and React Native. It acts as a true polyfill, meaning you can import it once and use the native fetch API everywhere without changing code. It is actively maintained and recommended by the authors of isomorphic-fetch as the replacement.

  • isomorphic-fetch:

    Do not choose isomorphic-fetch for new projects as it is deprecated and no longer maintained. The maintainers explicitly recommend migrating to cross-fetch. Only consider this if you are maintaining a legacy codebase that cannot be refactored immediately, but plan to replace it soon.

  • node-fetch:

    Choose node-fetch if you are building a backend service running exclusively on Node.js and do not need browser compatibility. Be aware that version 3 is ESM only, requiring module configuration changes, while version 2 supports CommonJS. It is ideal for server-side scripts where bundle size and browser polyfills are not concerns.

README for cross-fetch

cross-fetch
NPM Version Downloads Per Week License: MIT CI codecov

Universal WHATWG Fetch API for Node, Browsers, Workers and React Native. The scenario that cross-fetch really shines is when the same JavaScript codebase needs to run on different platforms.

  • Platform agnostic: browsers, Node or React Native
  • Optional polyfill: it's up to you if something is going to be added to the global object or not
  • Simple interface: no instantiation, no configuration and no extra dependency
  • WHATWG compliant: it works the same way wherever your code runs
  • TypeScript support: better development experience with types.
  • Worker support: works on different types of workers such as Service Workers and CloudFlare Workers

Table of Contents


Install

npm install --save cross-fetch

As a ponyfill (imports locally):

// Using ES6 modules with Babel or TypeScript
import fetch from 'cross-fetch';

// Using CommonJS modules
const fetch = require('cross-fetch');

As a polyfill (installs globally):

// Using ES6 modules
import 'cross-fetch/polyfill';

// Using CommonJS modules
require('cross-fetch/polyfill');

The CDN build is also available on unpkg:

<script src="//unpkg.com/cross-fetch/dist/cross-fetch.js"></script>

This adds the fetch function to the window object. Note that this is not UMD compatible.


Usage

With promises:

import fetch from 'cross-fetch';
// Or just: import 'cross-fetch/polyfill';

fetch('//api.github.com/users/lquixada')
  .then(res => {
    if (res.status >= 400) {
      throw new Error("Bad response from server");
    }
    return res.json();
  })
  .then(user => {
    console.log(user);
  })
  .catch(err => {
    console.error(err);
  });

With async/await:

import fetch from 'cross-fetch';
// Or just: import 'cross-fetch/polyfill';

(async () => {
  try {
    const res = await fetch('//api.github.com/users/lquixada');
    
    if (res.status >= 400) {
      throw new Error("Bad response from server");
    }
    
    const user = await res.json();
  
    console.log(user);
  } catch (err) {
    console.error(err);
  }
})();

Demo & API

You can find a comprehensive doc at Github's fetch page. If you want to play with cross-fetch, check our JSFiddle playground.

Tip: Run the fiddle on various browsers and with different settings (for instance: cross-domain requests, wrong urls or text requests). Don't forget to open the console in the test suite page and play around.

FAQ

Yet another fetch library?

I did a lot of research in order to find a fetch library that could be simple, cross-platform and provide polyfill as an option. There's a plethora of libs out there but none could match those requirements.

Why polyfill might not be a good idea?

In a word? Risk. If the spec changes in the future, it might be problematic to debug. Read more about it on sindresorhus's ponyfill page. It's up to you if you're fine with it or not.

How does cross-fetch work?

Just like isomorphic-fetch, it is just a proxy. If you're in node, it delivers you the node-fetch library, if you're in a browser or React Native, it delivers you the github's whatwg-fetch. The same strategy applies whether you're using polyfill or ponyfill.

Who's Using It?

The New York TimesApollo GraphQLFacebookSwaggerVulcanJSgraphql-request
The New York TimesApollo GraphQLFacebookSwaggerVulcanJSgraphql-request

Thanks

Heavily inspired by the works of matthew-andrews. Kudos to him!

License

cross-fetch is licensed under the MIT license Β© Leonardo QuixadΓ‘

Author

@lquixada
@lquixada