Convert Curl to JavaScript Fetch

fetch() takes a URL and an options object that lines up closely with curl's flags. The translation is short. What changes is the environment: in a browser, rules apply that curl has never heard of.

Last updated . How this page is checked.

The command

curl -X POST https://httpbin.org/post \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name":"Ada","role":"admin"}'

Curl flag to fetch option

curlfetch()
-X METHODmethod: "METHOD" (never inferred from the body)
-H "K: v"headers: { "K": "v" }
-d '{"a":1}'body: JSON.stringify({ a: 1 })
-d "a=1&b=2"body: new URLSearchParams({ a: "1", b: "2" })
-F "file=@x.png"body: formData (a FormData object)
-u user:pwheaders: { Authorization: "Basic " + btoa("user:pw") }
-b "k=v"browser: credentials: "include"; Node: a Cookie header
-Ldefault; redirect: "manual" or "error" to change
-m 20signal: AbortSignal.timeout(20000)
-kno browser equivalent

The same request with fetch

Two things curl does for you have to be written out. The method: curl switches to POST when it sees -d, while fetch stays on GET unless told, and a GET with a body throws. And the error check: fetch only rejects on network failure, so a 404 or 500 resolves normally and you must test response.ok.

const response = await fetch("https://httpbin.org/post", {
  method: "POST",
  headers: {
    "Authorization": "Bearer " + token,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ name: "Ada", role: "admin" }),
  signal: AbortSignal.timeout(20000),
});

if (!response.ok) throw new Error("HTTP " + response.status);
const data = await response.json();

What the browser adds

A curl command that works can fail as soon as the same request runs in a web page, for reasons that have nothing to do with your code. CORS: the browser will not let a script read a cross-origin response unless the server sends Access-Control-Allow-Origin, and a request with a JSON body or an Authorization header triggers a preflight the server must also approve. Forbidden headers: scripts cannot set User-Agent, Host, Cookie and several others; the browser controls them. Cookies are attached by the browser's own rules, and only cross-origin if you set credentials: "include".

And a secret in front-end code is public. A token that was safe in a shell variable is readable by every visitor once it is in a script; requests that need one belong on a server.

Uploads and forms

For -F, build a FormData object and pass it as the body. Do not set Content-Type: the runtime writes the multipart header with its boundary, exactly as curl does. For URL-encoded forms, URLSearchParams encodes the values and sets the form content type.

const form = new FormData();
form.append("caption", "Portrait, 1843");
form.append("avatar", fileInput.files[0]);
await fetch("https://httpbin.org/post", { method: "POST", body: form });

Common mistakes

  • fetch follows redirects by default; curl does not. A translated command may return a different page.
  • There is no -k in a browser. In Node the equivalent is a custom agent or dispatcher, with the same risks.
  • response.json() throws on an empty body, such as a 204. Check the status first.

Related curl examples

More under Converting curl

References

These links leave api-tester.com, which is independent of the projects they point to.

FAQ

How do I convert curl to JavaScript fetch?

Pass the URL to fetch with an options object: method for -X, headers for -H, and body for -d. Set the method explicitly, because fetch does not infer POST from a body.

What is the fetch equivalent of curl -d?

The body option. Use JSON.stringify(object) with a JSON Content-Type header, or a URLSearchParams object for form-encoded data.

Why does my curl command work but fetch fails?

In a browser, fetch is subject to CORS and cannot set certain headers. The server must return the right Access-Control-Allow headers for a cross-origin request to succeed.