Imagine you receive a sealed envelope in the mail with no writing on it at all. You have no idea whether it contains a letter, a photo, a cheque, or a concert ticket. You would have to tear it open and guess. Computers face the same problem when data travels across the web: a response is just a stream of bytes, and bytes alone do not announce what they are. A picture and a paragraph of text both arrive as ones and zeros.
This is exactly the problem that MIME types solve. A MIME type is a short label that says, “This is an image,” or “This is a web page,” or “This is some JSON data.” The browser reads that label and decides what to do with the body it just received. In this article you will learn what MIME types are, how the Content-Type header carries them, why getting the label right genuinely matters, and which types you will run into most often.
What is a MIME type?
MIME stands for Multipurpose Internet Mail Extensions. The name comes from email, where this labelling system was first invented to let messages carry attachments like images and documents. The web borrowed the same idea, so today you will also hear MIME types called media types or content types. They all mean the same thing.
A MIME type is always written as two parts separated by a slash:
type/subtype
The first part, the type, is a broad family: text, image, audio, video, or application (used for everything that does not fit the other families, including most data formats). The second part, the subtype, is the specific format within that family. So image/png means “an image, specifically in PNG format,” and text/html means “text, specifically an HTML document.”
Here are a few read in plain English:
text/html-> an HTML web pageapplication/json-> JSON dataimage/png-> a PNG imagetext/css-> a stylesheetapplication/javascript-> a JavaScript file
That is the whole grammar. Once you can read the slash, you can read any MIME type you meet.
The Content-Type header carries the label
A MIME type on its own is just a string. It needs a place to ride along with the data, and that place is an HTTP header called Content-Type. Every time a server sends you something, it can include this header to declare what the body is.
Here is what a server’s response might look like when it sends a web page:
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Content-Length: 1270
<!DOCTYPE html>
<html>
<head><title>Hello</title></head>
<body><h1>Welcome</h1></body>
</html>
Notice the Content-Type: text/html; charset=utf-8 line. The first part is the MIME type. The bit after the semicolon, charset=utf-8, is an optional parameter that tells the browser which character encoding the text uses, so accented letters and other characters display correctly. Parameters always come after a semicolon, and not every type uses them.
The flow looks like this:
Browser Server
| GET /page.html |
| ----------------------------> |
| |
| 200 OK |
| Content-Type: text/html |
| <html>...</html> |
| <---------------------------- |
| |
"It's HTML — render it as a page"
The same header works in the other direction too. When your browser (or a program) sends data to a server, for example submitting a form or uploading JSON to an API, it sets Content-Type on the request so the server knows how to read the body it is being handed.
Header, not file extension
The browser trusts the Content-Type header far more than it trusts the file name. A file called data.json served with Content-Type: text/html will be treated as HTML, not JSON. The header is the source of truth on the web.
Why the right type actually matters
It is tempting to think of the label as a polite formality. It is not. The MIME type changes the browser’s behaviour completely, and the wrong one breaks things in confusing ways.
Consider an API that returns some data. If the server correctly sends Content-Type: application/json, a browser tool or a JavaScript program knows it is JSON and can parse it into usable values. But if the same response goes out as Content-Type: text/html, the browser may try to interpret the curly braces and quotes as markup, or your code may refuse to parse it. The bytes did not change at all; only the label did, and that was enough to break everything.
Same bytes, different label:
{"user":"Jane Doe","active":true}
with Content-Type: application/json -> parsed as data, works
with Content-Type: text/html -> treated as a web page, breaks
A few real consequences of a wrong or missing type:
- A stylesheet sent as
text/plainis often ignored, so your page loads with no styling at all. - A JavaScript file sent with the wrong type may be refused by the browser for security reasons, and your scripts never run.
- An image sent as
text/htmlshows up as a wall of strange characters instead of a picture. - A PDF sent as
application/octet-streammay force a download instead of opening in the browser’s viewer.
Don't rely on the browser guessing
When a type is missing or clearly wrong, some browsers try to sniff the content and guess what it really is. This guessing is inconsistent and can even be a security risk, which is why many servers send the header X-Content-Type-Options: nosniff to switch guessing off. The lesson: set the correct Content-Type yourself instead of hoping the browser figures it out.
A table of common MIME types
You will not need to memorise hundreds of these. A small handful covers the vast majority of everyday web work. Keep this table nearby until they become second nature.
| MIME type | What it is | Typical use |
|---|---|---|
text/html |
An HTML document | Web pages |
text/css |
A stylesheet | Page styling |
text/plain |
Unformatted text | Logs, raw text files |
text/csv |
Comma-separated values | Spreadsheet-style data |
application/json |
JSON data | APIs, config files |
application/javascript |
JavaScript code | Scripts (also seen as text/javascript) |
application/xml |
XML data | Feeds, older APIs |
application/pdf |
A PDF document | Documents, invoices |
application/octet-stream |
Generic binary “unknown” | Downloads, files of no specific type |
multipart/form-data |
A form with file uploads | Submitting forms with files |
image/png |
A PNG image | Logos, screenshots |
image/jpeg |
A JPEG image | Photos |
image/svg+xml |
An SVG vector image | Icons, illustrations |
image/webp |
A WebP image | Modern, smaller images |
audio/mpeg |
An MP3 audio file | Music, podcasts |
video/mp4 |
An MP4 video file | Video playback |
A couple of patterns are worth noticing. Anything binary and unidentified tends to be application/octet-stream, which is the digital equivalent of an unlabelled box. And some formats borrow the +xml or +json suffix (like image/svg+xml) to say “this is fundamentally XML or JSON, but used for a specific purpose.”
Setting the type in practice
You rarely write MIME types out by hand for static files. Web servers keep a built-in mapping from file extensions to MIME types, so a file ending in .css is automatically served as text/css. The cases where you do think about it are usually two:
First, when you build an API or send a response from your own code, you set the header explicitly. In a small server you might write something like this:
// A tiny example: replying with JSON
response.setHeader("Content-Type", "application/json");
response.end(JSON.stringify({ user: "John Doe", active: true }));
Second, when you send a request that has a body, such as posting data to an API, you tell the server what you are sending:
POST /api/users HTTP/1.1
Host: blog.acy-partner.com
Content-Type: application/json
{"name":"John Doe","role":"editor"}
The server reads that Content-Type and knows to parse the body as JSON rather than as form fields or plain text.
When debugging, check the header first
If a page looks unstyled, a script never runs, or an API response will not parse, open your browser’s developer tools, look at the Network tab, click the request, and read its Content-Type. A surprising number of “mystery” bugs are simply a wrong or missing media type.
Recap
A MIME type is a short, two-part label, written as type/subtype, that tells software what kind of data it is looking at. The Content-Type HTTP header is how that label travels with both responses and requests, and the browser uses it to decide whether to render a page, display an image, run a script, or hand you a download. Because the label drives behaviour, getting it wrong quietly breaks styling, scripts, APIs, and more, which is why you set it deliberately rather than leaving the browser to guess.
You now have the vocabulary to read any media type you encounter and the common table to lean on. From here, a natural next step is to look more closely at HTTP headers in general and at how status codes, caching, and content negotiation work together to shape what a browser actually does with the bytes it receives.