# Content-Type Header — Syntax, Values & Examples

> 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.

- Type: Request & response header
- Category: Content
- Defined in: [RFC 9110 §8.3 — Content-Type](https://www.rfc-editor.org/rfc/rfc9110.html#section-8.3)

## Syntax

```http
Content-Type: <type>/<subtype>[; charset=<encoding>][; boundary=<boundary>]
```

## Values

| Value | Meaning |
|---|---|
| `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

```http
Content-Type: application/json
```

API requests and responses

```http
Content-Type: text/html; charset=utf-8
```

web pages

## Good to know

- When sending `FormData` with fetch, don't set Content-Type yourself — the browser adds the multipart boundary.
- `application/json` on a cross-origin request triggers a CORS preflight.
- Pair it with `X-Content-Type-Options: nosniff` so browsers trust the declared type.

## How to set Content-Type

### Express

```
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 bodies
```

### Next.js (route handler)

```
return Response.json({ ok: true }); // application/json

return new Response(csv, {
  headers: { "Content-Type": "text/csv; charset=utf-8" },
});
```

### fetch (request body)

```
await fetch("/api/items", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ name: "widget" }),
});
```

### curl

```
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/items
```

## Check it

Fetch only the response headers and filter for Content-Type. In the browser, it's under Response Headers in DevTools → Network.

```sh
curl -sI https://example.com/ | grep -i '^content-type:'
```

## FAQ

### 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.

## Status codes it appears with

- [415 Unsupported Media Type](https://www.devkult.com/http/415.md)

## Related headers

- [Accept](https://www.devkult.com/headers/accept.md): Lists the response media types the client can handle, in order of preference.
- [Content-Length](https://www.devkult.com/headers/content-length.md): The size of the message body in bytes.
- [X-Content-Type-Options](https://www.devkult.com/headers/x-content-type-options.md): With nosniff, stops browsers guessing a response's type, so a text file can't be run as a script.
- [Content-Disposition](https://www.devkult.com/headers/content-disposition.md): Tells the browser to display a response inline or download it as a file, and with what file name.

## Further reading

- [MIME types by file extension](https://www.devkult.com/mime.md)
- [JSON formatter](https://www.devkult.com/tools/json/json-formatter.md)
- [Unexpected token in JSON](https://www.devkult.com/blog/unexpected-token-in-json.md)

Open the interactive page: https://www.devkult.com/headers/content-type