Content-Type
request & response headercontent
States the media type of the body — HTML, JSON, form data, an image — and often its character encoding.
On a response, Content-Type tells the browser how to handle the body: render HTML, parse JSON, display an image. On a request, it tells the server how to parse what you sent — the usual cause of an empty req.body is a missing or wrong Content-Type.
Syntax
Content-Type: <type>/<subtype>[; charset=<encoding>][; boundary=<boundary>]
Defined in RFC 9110 §8.3 — Content-Type.
Values
| application/json | JSON — UTF-8 by definition, so no charset needed |
|---|---|
| text/html; charset=utf-8 | an HTML page |
| application/x-www-form-urlencoded | a classic HTML form: a=1&b=2 |
| multipart/form-data; boundary=… | forms with file uploads |
| text/plain; charset=utf-8 | plain text |
| application/octet-stream | arbitrary binary data |
Examples
Content-Type: application/json
API requests and responses
Content-Type: text/html; charset=utf-8
web pages
Good to know
- When sending
FormDatawith fetch, don't set Content-Type yourself — the browser adds the multipart boundary. application/jsonon a cross-origin request triggers a CORS preflight.- Pair it with
X-Content-Type-Options: nosniffso browsers trust the declared type.
Further reading: MIME types by file extension · JSON formatter · Unexpected token in JSON
How to set Content-Type
res.json({ ok: true }); // sets Content-Type: application/json
res.type("html").send(html); // text/html; charset=utf-8
app.use(express.json()); // parse JSON request bodiesreturn Response.json({ ok: true }); // application/json
return new Response(csv, {
headers: { "Content-Type": "text/csv; charset=utf-8" },
});await fetch("/api/items", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ name: "widget" }),
});curl -X POST -H 'Content-Type: application/json' \
-d '{"name":"widget"}' https://api.example.com/items
# --json sets Content-Type and Accept for you (curl 7.82+):
curl --json '{"name":"widget"}' https://api.example.com/itemsCheck it
Fetch only the response headers and filter for Content-Type. In the browser, it's under Response Headers in DevTools → Network.
curl -sI https://example.com/ | grep -i '^content-type:'
To compare response headers across many URLs at once, use the HTTP Status Checker.
Frequently asked questions
Why is req.body empty in Express?
Either the client didn't send Content-Type: application/json, or no body parser is installed — add app.use(express.json()).
Should I add charset=utf-8 to application/json?
It's harmless but unnecessary: JSON is defined as UTF-8, and the media type has no charset parameter.