Skip to content

Convert curl commands to axios (and back)

· 8 min read

Every API's documentation gives you a curl command. Your code needs an axios call. The translation looks mechanical until a request that works in the terminal returns a 400 from JavaScript — usually because a flag you skimmed past changed the body encoding, or because axios helpfully did something curl would never do. Here is how the flags actually map, in both directions, and where the translation quietly goes wrong.

The core mapping

curlaxiosfetch
-X POSTmethod: "post"method: "POST"
-H "K: V"headers: { K: "V" }headers: { K: "V" }
-d '{"a":1}'data: { a: 1 }body: JSON.stringify(...)
-u user:passauth: { username, password }manual Authorization header
--json '...'data + JSON content typebody + JSON content type

The trap: -d does not mean JSON

This is the single most common cause of a working curl command failing as axios. Plain -d sends application/x-www-form-urlencoded, not JSON. If the docs show:

curl -X POST https://api.example.com/items -d '{"name":"test"}'

…then curl sends that JSON string as a form body with a form content type. Many APIs parse it anyway because they sniff the content, and many do not. Translate it to axios as an object and axios will send real JSON with application/json — a different request from the one you tested. Sometimes that fixes things; sometimes it breaks an endpoint that only accepts form encoding.

The fix is to be explicit. If the API wants JSON, the curl command should have said -H "Content-Type: application/json" or used --json. If it genuinely wants form encoding, send URLSearchParams from axios rather than a plain object.

Other differences that bite

Redirects

curl does not follow redirects unless you pass -L. Browsers and axios follow them by default. A command that returns a 301 body in your terminal may silently land on a different endpoint from JavaScript.

Compression

--compressed asks for gzip. In the browser this is automatic and not something you control, so the flag has no equivalent — drop it.

-k / --insecure

There is no browser equivalent, and that is deliberate. If a request needs -k to work, it has a broken certificate, and no amount of JavaScript will let you skip that check from a page. Fix the certificate.

Cookies and credentials

curl sends whatever you give it. A browser applies same-origin rules: cross-origin requests omit cookies unless you set withCredentials: true in axios (or credentials: "include" in fetch) and the server sends matching CORS headers. A great many "works in curl, fails in the browser" reports are simply CORS, which curl does not participate in at all.

Error handling

axios rejects on 4xx and 5xx; fetch does not — it resolves, and you have to check response.ok yourself. Translating axios code to fetch without adding that check is how a 500 gets silently treated as success.

Going the other way: axios to curl

Reproducing a failing request on the command line is one of the fastest debugging moves available. Take the method, URL, headers, and body from the request config and write them out as -X, -H, and -d. Two things to remember: serialize the body yourself (axios does it for you, curl will not), and add -H "Content-Type: application/json" explicitly, since that header was implicit in the axios call.

Your browser can do most of this for you: in DevTools → Network, right-click a request and choose "Copy as cURL". Which brings up the reason to be careful about where you paste the result.

Why the conversion should happen locally

A curl command copied from DevTools or from a colleague's terminal is rarely clean. It carries the Authorization header with a live bearer token, session cookies, API keys, and sometimes a request body full of customer data. Pasting that into an online converter sends every one of those secrets to a stranger's server, where it lands in request logs you cannot inspect or purge.

KeepItLocally's curl converter parses the command in your browser and never transmits it. It handles -X, -H, -d and its --data-* variants, --json, and -u, and it ignores the transport-only flags (-L, -s, -k, --compressed) that have no meaning in JavaScript. Multipart -F uploads are not supported yet — it will tell you so rather than emit something subtly wrong.

If a token has already gone through an online converter, rotate it. That is cheaper than finding out later where the logs ended up.

Quick reference

  • -d is form-encoded unless a JSON content type says otherwise.
  • curl ignores CORS — the browser does not.
  • curl needs -L to follow redirects; axios follows by default.
  • fetch does not throw on 4xx/5xx — check response.ok.
  • Copied curl commands contain live credentials — convert them locally.

Working with tokens from those headers? See how to verify a JWT signature, or decode one with the JWT decoder.