How Axios Switches Between Browser and Node.js
Axios is an isomorphic (universal) HTTP client capable of running seamlessly in both client-side browser runtimes and server-side Node.js environments using the exact same API. It accomplishes this environment switching through an internal adapter design pattern combined with automated runtime detection and package build configurations. Depending on where the code executes, Axios dynamically delegates network calls to either the browser's native networking APIs or Node.js's built-in networking modules.
The Adapter Pattern
At the core of Axios’s environment-switching mechanism is the adapter pattern. Axios separates the high-level request/response handling (such as interceptors, transformations, and configuration merging) from the low-level network dispatching.
The dispatching is handled by dedicated adapters:
- Browser Adapter (
xhr.js): Interacts with the browser's nativeXMLHttpRequest(or Fetch API in newer/custom setups) to manage network requests, handle CORS, and track upload/download progress. - Node.js Adapter (
http.js): Interacts with Node's nativehttpandhttpsmodules, handling server-side concerns such as streams, HTTP/HTTPS proxies, and SSL certificates.
Build-Time Resolution via
package.json
Modern module bundlers (such as Webpack, Rollup, and Vite) resolve
the correct adapter at build time through conditional exports in Axios's
package.json.
Axios defines fields like "browser" and conditional
subpath "exports". When a bundler compiles an application
for the web, it checks these fields and automatically substitutes the
Node.js implementation with the browser implementation. This ensures
that Node-specific APIs (which do not exist in the browser) are omitted
from client-side bundles, reducing bundle size and preventing runtime
errors.
Runtime Environment Detection
If the environment is not determined at build time, Axios detects the environment at runtime by inspecting global variables:
- Checking for Node.js: Axios verifies if the runtime
includes Node-specific identifiers, such as checking if
typeof process !== 'undefined'andprocess.versions.nodeexists. - Checking for the Browser: Axios checks for the
presence of browser-specific globals like
windowordocument, as well asXMLHttpRequest.
Based on the evaluation of these global objects, Axios automatically assigns the appropriate default adapter to the request configuration.
Custom and Manual Adapter Configuration
Axios also allows developers to override the default switching
mechanism manually. By defining the adapter property within
the Axios configuration object, developers can enforce a specific
transport layer or provide custom adapters for alternative environments,
such as Web Workers, Service Workers, or testing mocks:
// Example: Explicitly defining a custom adapter
axios.get('/api/data', {
adapter: 'fetch' // Or a custom adapter function
});Through the combination of package.json module mapping,
runtime global detection, and the adapter architecture, Axios provides a
unified interface across distinct JavaScript execution environments.