How to Convert cURL to Fetch or Axios Automatically (2026)
You have a cURL command from an API's documentation or Chrome DevTools, and you need it as JavaScript. This guide covers every automatic and manual conversion path — from online tools to hand-rolling your own conversions for fetch and Axios — with side-by-side examples for every pattern.
3 min
average time to manually convert
< 30s
with an automatic converter
fetch vs Axios
2 main JS HTTP libraries
100%
of cURL flags have equivalents
Why Convert cURL at All?
cURL is the universal language of HTTP. API vendors write their docs in cURL because it works everywhere. Chrome DevTools lets you copy any network request as cURL. When you need that request inside a JavaScript app, you must translate it — and doing that by hand for complex requests with many headers and auth tokens is error-prone.
API documentation
Nearly every API provider (Stripe, Twilio, GitHub, AWS) shows request examples as cURL commands you need to translate.
Chrome DevTools
Right-clicking any network request gives "Copy as cURL" — an instant snapshot of the exact request including cookies and headers.
Postman / Insomnia
Both tools let you import cURL commands and export them as JavaScript. The reverse is also common.
Team communication
cURL is the easiest way to share a reproducible HTTP request with a colleague regardless of their tech stack.
Automatic Conversion Tools
The fastest path is to use an automatic converter. Here are the best options:
curlconverter.com
The most popular online tool. Paste any cURL command and it outputs fetch, Axios, Python requests, and 20+ other languages. Open source.
UnblockDevs cURL Converter Tool
Available at /curl-converter on this site. Converts to fetch and Axios with formatted, production-ready output including async/await patterns.
Postman Import
In Postman, File > Import > Raw text > paste cURL. Postman parses it into a full request with headers, body, and auth. Then use "Code" panel to export as JavaScript.
VS Code Extensions
Extensions like "REST Client" and "Thunder Client" accept cURL syntax directly in .http files and can convert to JavaScript.
Best automatic workflow
Manual Conversion: cURL to Fetch
Understanding the manual mapping helps you debug issues with automatic converters and handle edge cases. Here is the complete flag-to-option mapping:
| Item | cURL | fetch() |
|---|---|---|
| URL | curl https://api.example.com | fetch('https://api.example.com') |
| POST method | -X POST | method: 'POST' |
| Header | -H 'Content-Type: application/json' | headers: { 'Content-Type': 'application/json' } |
| JSON body | -d '{"key":"val"}' | body: JSON.stringify({ key: 'val' }) |
| Form body | -d 'key=val' | body: new URLSearchParams({ key: 'val' }) |
| Basic auth | -u user:pass | headers: { Authorization: 'Basic ' + btoa('user:pass') } |
| Bearer token | -H 'Authorization: Bearer TOKEN' | headers: { Authorization: 'Bearer TOKEN' } |
| Cookies | --cookie "sid=abc" | credentials: 'include' |
| Follow redirects | -L | redirect: 'follow' (default) |
// Original cURL:
// curl -X POST https://api.example.com/login \
// -H "Content-Type: application/json" \
// -H "Accept: application/json" \
// -d '{"username":"alice","password":"secret"}'
// Converted to fetch (async/await):
async function login(username, password) {
const response = await fetch('https://api.example.com/login', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
},
body: JSON.stringify({ username, password }),
});
if (!response.ok) {
throw new Error(`Login failed: ${response.status}`);
}
return response.json();
}Manual Conversion: cURL to Axios
Axios has a slightly different API than fetch. The key differences are that Axios automatically serializes JSON bodies, automatically parses JSON responses, and throws errors for non-2xx status codes.
| Item | cURL | Axios |
|---|---|---|
| URL | curl https://api.example.com | axios.get('https://api.example.com') |
| POST method | -X POST | method: 'post' |
| Header | -H 'Authorization: Bearer TOKEN' | headers: { Authorization: 'Bearer TOKEN' } |
| JSON body | -d '{"key":"val"}' | data: { key: "val" } // no stringify needed |
| Form body | -d 'key=val' | data: new URLSearchParams({ key: 'val' }) |
| Basic auth | -u user:pass | auth: { username: 'user', password: 'pass' } |
| Timeout | --max-time 10 | timeout: 10000 // milliseconds |
| Query params | curl url?key=val | params: { key: 'val' } |
import axios from 'axios';
// Original cURL:
// curl -X POST https://api.example.com/users \
// -H "Authorization: Bearer TOKEN" \
// -H "Content-Type: application/json" \
// -d '{"name":"Alice","role":"admin"}'
// Converted to Axios:
async function createUser(token, userData) {
// Axios auto-serializes data to JSON and sets Content-Type
const response = await axios.post('https://api.example.com/users', userData, {
headers: {
'Authorization': `Bearer ${token}`,
},
});
// Axios auto-parses JSON and puts it in response.data
return response.data;
}
// Axios also throws automatically on 4xx/5xx:
try {
const user = await createUser('mytoken', { name: 'Alice', role: 'admin' });
} catch (error) {
if (axios.isAxiosError(error)) {
console.error('Status:', error.response?.status);
console.error('Message:', error.response?.data?.message);
}
}Fetch vs Axios: Which Should You Use?
| Item | fetch (built-in) | axios (library) |
|---|---|---|
| Installation | Built-in, no install needed | npm install axios |
| JSON body | Must use JSON.stringify() | Automatic (just pass object) |
| JSON response | Must call response.json() | Automatic (in response.data) |
| Error on 4xx/5xx | No — must check response.ok | Yes — throws automatically |
| Request timeout | Requires AbortController | Built-in timeout option |
| Request interceptors | Not built-in | Built-in interceptors |
| Cancel requests | AbortController | CancelToken or AbortController |
| Upload progress | Not available | onUploadProgress callback |
| Bundle size | 0 KB (browser native) | ~13 KB minified+gzipped |
Quick fact
For new projects targeting modern browsers or Node.js 18+, the built-in fetch API is usually sufficient. Choose Axios when you need interceptors, upload progress, automatic error throwing, or need to support older environments.
Handling Complex cURL Commands
Some cURL commands have tricky patterns. Here are the most common edge cases and how to handle them:
Multi-line cURL with backslash continuation
cURL commands are often split across lines with trailing backslashes for readability. Join them into a single logical command before converting.
// Multi-line cURL (backslashes are line continuations):
// curl -X POST \
// -H "Content-Type: application/json" \
// -d '{"key":"val"}' \
// https://api.example.com/endpoint
// All flags apply to the same request — treat as:
// curl -X POST -H "Content-Type: application/json" -d '{"key":"val"}' https://api.example.com/endpoint--data-raw vs -d
--data-raw is like -d but does not process @ file references. Both convert the same way to the body option.
// cURL: curl --data-raw '{"token":"abc@example.com"}' https://api.example.com
// The @ is treated as literal text with --data-raw
const response = await fetch('https://api.example.com', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: '{"token":"abc@example.com"}', // or JSON.stringify
});URL-encoded vs JSON body
Check the Content-Type header to determine how to encode the body. application/json uses JSON.stringify, application/x-www-form-urlencoded uses URLSearchParams.
// application/x-www-form-urlencoded (HTML forms)
const form = new URLSearchParams();
form.append('grant_type', 'client_credentials');
form.append('client_id', 'myapp');
const response = await fetch('https://auth.example.com/token', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: form.toString(),
});cURL with cookies (--cookie or -b)
Browser cookies are managed by the browser itself. Use credentials: "include" to send stored cookies, or set Cookie header explicitly if you have the value.
// cURL: curl --cookie "session=abc123; csrf=xyz" https://api.example.com/data
// Option 1: Let browser handle cookies automatically
const response = await fetch('https://api.example.com/data', {
credentials: 'include',
});
// Option 2: Set explicitly (server-side Node.js only, not browsers)
const response2 = await fetch('https://api.example.com/data', {
headers: { 'Cookie': 'session=abc123; csrf=xyz' },
});Converting to Axios with Base Instance
If you are converting multiple cURL commands that share the same base URL and auth, use an Axios instance to avoid repetition:
import axios from 'axios';
// Create a reusable instance with shared config
const api = axios.create({
baseURL: 'https://api.example.com/v1',
timeout: 10000,
headers: {
'Authorization': `Bearer ${process.env.API_TOKEN}`,
'Content-Type': 'application/json',
},
});
// Add request interceptor for dynamic tokens
api.interceptors.request.use((config) => {
// Refresh token logic here if needed
return config;
});
// Add response interceptor for error handling
api.interceptors.response.use(
(response) => response.data,
(error) => {
if (error.response?.status === 401) {
// Handle auth failure
window.location.href = '/login';
}
return Promise.reject(error);
}
);
// Now all requests share base URL and headers:
// cURL: curl https://api.example.com/v1/users
const users = await api.get('/users');
// cURL: curl -X POST https://api.example.com/v1/users -d '{"name":"Alice"}'
const newUser = await api.post('/users', { name: 'Alice' });Error Handling After Conversion
One of the biggest differences between cURL and JavaScript is error handling. cURL exits with a non-zero code. JavaScript requires explicit handling.
No error handling
// Naive conversion - no error handling
const response = await fetch('https://api.example.com/data');
const data = await response.json(); // Crashes if HTML error page returned
console.log(data);Production-ready wrapper
// Production-ready fetch with proper error handling
async function apiFetch(url, options = {}) {
const response = await fetch(url, options);
if (!response.ok) {
let errorMessage = `HTTP ${response.status}: ${response.statusText}`;
try {
const errorBody = await response.json();
errorMessage = errorBody.message || errorBody.error || errorMessage;
} catch {
// Response wasn't JSON, use status text
}
throw new Error(errorMessage);
}
const contentType = response.headers.get('content-type');
if (contentType?.includes('application/json')) {
return response.json();
}
return response.text();
}