Migrates code from the Axios HTTP client to the WHATWG Fetch API that is natively available in Node.js as the global fetch, reducing dependencies and improving performance. It rewrites every Axios request helper — axios.request(), axios.get(), axios.delete(), axios.head(), axios.options(), axios.post(), axios.put(), axios.patch(), axios.postForm(), axios.putForm(), and axios.patchForm() — and recognizes default ESM imports, aliased imports, CommonJS require() calls, and dynamic import(). Once all call sites are converted, it also removes the axios and @types/axios entries from package.json.
Run this codemod with:
npx codemod @nodejs/axios-to-whatwg-fetchA plain axios.get() becomes a fetch() call with a shim that keeps the response.data property working.
-import axios from "axios";
const base = "https://dummyjson.com/todos";
-const all = await axios.get(base);
+const all = await fetch(base)
+ .then(async (res) => Object.assign(res, { data: await res.json() }))
+ .catch(() => null);
console.log("\nGET /todos ->", all.status);
console.log(`Preview: ${all.data.todos.length} todos`);The data argument of axios.post() is serialized with JSON.stringify() and passed as the body option.
-import axios from 'axios';
const base = 'https://dummyjson.com/todos/add';
-const todoCreated = await axios.post(base, {
- todo: 'Use DummyJSON in the project',
- completed: false,
- userId: 5,
-});
+const todoCreated = await fetch(base, {
+ method: "POST",
+ body: JSON.stringify({
+ todo: 'Use DummyJSON in the project',
+ completed: false,
+ userId: 5,
+ })
+})
+ .then(async (resp) => Object.assign(resp, { data: await resp.json() }))
+ .catch(() => null);
console.log('\nPOST /todos ->', todoCreated);axios.postForm() (and the putForm/patchForm variants) send the payload as URLSearchParams.
-import axios from 'axios';
const base = 'https://dummyjson.com/forms';
-const created = await axios.postForm(`${base}/submit`, {
- title: 'Form Demo',
- completed: false,
-});
+const created = await fetch(`${base}/submit`, {
+ method: "POST",
+ body: new URLSearchParams({
+ title: 'Form Demo',
+ completed: false,
+ })
+})
+ .then(async (resp) => Object.assign(resp, { data: await resp.json() }))
+ .catch(() => null);
console.log(created);The url, method, and data properties of the config object are mapped onto the fetch() call.
-import axios from 'axios';
-
const base = 'https://dummyjson.com/todos/1';
-const customRequest = await axios.request({
- url: base,
- method: 'PATCH',
- data: {
- todo: 'Updated todo',
- completed: true,
- },
-});
+const customRequest = await fetch(base, {
+ method: "PATCH",
+ body: JSON.stringify({
+ todo: 'Updated todo',
+ completed: true,
+ })
+})
+ .then(async (resp) => Object.assign(resp, { data: await resp.json() }))
+ .catch(() => null);
console.log('\nREQUEST /todos/1 ->', customRequest);CommonJS modules are handled the same way, and the now-unused require('axios') binding is removed.
-const axios = require('axios');
function fetchAllTodos() {
- return axios.get('https://dummyjson.com/todos');
+ return fetch('https://dummyjson.com/todos')
+ .then(async (res) => Object.assign(res, { data: await res.json() }))
+ .catch(() => null);
}
module.exports = { fetchAllTodos };- A
fetchresponse exposes its payload throughres.json()rather than adataproperty, so each converted call is followed by.then(async (res) => Object.assign(res, { data: await res.json() }))to keep existingresponse.dataaccesses working. - Converted calls end with
.catch(() => null), so a failed request resolves tonullinstead of rejecting. Also note that unlike Axios,fetchdoes not reject on HTTP error statuses (4xx/5xx), so error-handling code built around Axios rejections should be reviewed manually. - Safety first: if any Axios call in a file uses an unsupported configuration option, the entire file is left untouched and a warning with the source location is printed, preserving the original behavior.
- After the transformation, the codemod detects your package manager and removes the
axiosand@types/axiosdependencies frompackage.json.
The codemod skips files whose Axios calls use any of the following configuration options, because they have no direct fetch equivalent:
beforeRedirectcancelTokendecompresshttpAgenthttpsAgentmaxBodyLengthmaxContentLengthmaxRedirectsparamsSerializersignalsocketPathtimeouttransformRequesttransformResponsevalidateStatuswithCredentials
It also does not cover Axios features outside of the direct request helpers, such as interceptors, cancel tokens, or instance configuration created with axios.create().