The Content-Type header is a small string with outsized power. Get it wrong and your CSS won't load, your download opens as gibberish in the browser, or an uploaded file runs as a script.
A file on the web is just a stream of bytes. Nothing about the bytes themselves says "this is an image" or "this is a stylesheet" or "this is a script to run." That decision is made by a short string in an HTTP header — the MIME type — and the browser takes it seriously. When it's right, everything just works and you never think about it. When it's wrong, you get one of a family of baffling bugs, and in the worst case, a security hole.
What a MIME type is
The proper name is media type, and it's more precise than the "MIME" nickname suggests. Wikipedia defines it:
"In information and communications technology, a media type, content type or MIME type is a two-part identifier for file formats and content formats. Their purpose is comparable to filename extensions and uniform type identifiers, in that they identify the intended data format."
— Wikipedia, "Media type" (CC BY-SA 4.0)
Two parts: a type and a subtype, like text/html, image/png, or application/json. The server sends it in the Content-Type header, and the browser uses it to decide what to do with the bytes.
The header beats the extension
A common misconception is that browsers decide what a file is from its .png or .js extension. On the web, they don't — the Content-Type header wins. Serve a perfectly good stylesheet with the wrong type and the browser refuses to apply it, even though the file is named styles.css and contains valid CSS. Serve a JSON API response as text/plain and some clients won't parse it. This is why "my CSS isn't loading" and "my font is being blocked" so often trace back not to the file but to the server sending the wrong Content-Type. The bytes are fine; the label is lying.
The security angle: mislabelled uploads
Here's where it stops being cosmetic. Imagine a site that lets users upload an avatar and serves it back. If an attacker uploads a file containing HTML and JavaScript, and the server serves it with Content-Type: text/html, the browser will render and execute it — in the context of your site. That's stored cross-site scripting, delivered entirely through a wrong content type. User-supplied files should be served with a correct, non-executable type (or as an explicit download), never with a type the browser will run. The MIME type isn't just metadata here; it's the line between "an image" and "a script running on your domain."
When the browser guesses: MIME sniffing
To be helpful, browsers historically "sniffed" content — if the declared type looked wrong, they'd inspect the bytes and guess. Helpful, and dangerous: sniffing is exactly what lets a file declared as an image get reinterpreted as HTML and executed. The defence is the X-Content-Type-Options: nosniff header, which tells the browser "trust my declared Content-Type, do not guess." Setting nosniff closes the sniffing-based attack path and makes your content types authoritative. Any site serving user content should send it. It's one header, and it removes a whole class of "the browser decided this image was a webpage" surprises.
Content-Disposition: download vs display
MIME type determines what the browser thinks a file is; the Content-Disposition header determines what it does with it. Set Content-Disposition: inline (or omit the header) and the browser tries to display the content — render a PDF, show an image, play a video. Set Content-Disposition: attachment; filename="report.pdf" and the browser downloads it instead, regardless of whether it could display it. This header is the difference between "click a PDF link and read it in the browser" and "click a link and get a download dialog." For user-uploaded files, forcing attachment is a security measure: even if the MIME type is wrong or the file is malicious, a download doesn't render in the page context. Combining a correct MIME type with Content-Disposition: attachment for untrusted files is the belt-and-suspenders approach.
Common MIME mistakes and their symptoms
A few specific MIME errors recur constantly, and each has a distinctive symptom. Serving a CSS file as text/plain causes the browser to refuse to apply the styles — the console logs a warning about MIME type mismatch, the stylesheet is fetched but ignored, and the page appears unstyled. Serving JavaScript as text/plain triggers the same refusal: the script loads but doesn't execute, and features silently break. Serving a font as application/octet-stream instead of font/woff2 causes cross-origin font loading to fail in some browsers. Serving JSON as text/html means the browser may try to render it as a webpage, and any HTML entities in the JSON become an XSS vector. Each of these is a one-line server configuration fix, but diagnosing them requires looking at the response headers, not the file content — which is why developers who don't check headers can spend hours chasing the wrong cause.
MIME types in API design
In REST APIs, the Content-Type header on a request tells the server what format the body is in, and the Accept header tells the server what format the client wants back. Getting these wrong produces a different class of bug: a 415 Unsupported Media Type response when the server doesn't recognise the request's content type, or a 406 Not Acceptable when the server can't produce the format the client requested. API clients that hardcode Content-Type: application/json will break against endpoints that expect multipart/form-data for file uploads, or application/x-www-form-urlencoded for legacy form submissions. The MIME type isn't just a browser concern — it's the contract that request and response bodies are interpreted through, and violating it produces errors that look like server bugs but are actually client-side labelling mistakes.
Get the type right at the source
Most MIME bugs come from the server not knowing, or not stating, the correct type. When a file behaves wrongly in the browser, check the declared type first with a MIME type lookup — map the extension to its correct Content-Type and confirm your server is actually sending that. Since the type travels alongside the response status, an HTTP status codes reference helps when you're reading a response and the status and content type together tell the story (a 200 serving the wrong type is a very different bug from a 404). And when a resource loads from an unexpected place, a URL parser helps confirm exactly what's being requested. A MIME type is a two-part string that decides how the browser treats your bytes — worth getting exactly right, especially when the bytes came from a user.