MIME Types, Explained

After reading this you will know what a MIME type is, how a server uses it to tell a browser what to do with a file, and why a wrong type breaks CSS, modules and fonts even when the bytes are perfect.

What a MIME type is

A MIME type is a short label that names the format of a file. It looks like text/css or image/png: a type, a slash, and a subtype. The name comes from Multipurpose Internet Mail Extensions, first defined for email in RFC 2045 and RFC 2046 (1996). The web adopted the same labels. Today the current registry lives with IANA, and the syntax for HTTP is pinned down by RFC 9110, section 8.3, which calls the label a media type.

Here is the hook. You upload a stylesheet named site.css to a server that sends it with the header Content-Type: text/plain. The bytes are a valid stylesheet. The browser still refuses to apply it, because a strict browser only honors a <link rel="stylesheet"> whose response type is text/css. The file did not change. The label did. That is the whole lesson in one example.

Where the type actually comes from

The file extension on disk is a hint, not a fact. What the browser reads is the Content-Type response header the server sends. A typical exchange looks like this:

\text{GET /site.css} \;\rightarrow\; \text{Content-Type: text/css; charset=utf-8}

The value has two parts. Before the semicolon is the media type, text/css. After it are optional parameters, here charset=utf-8, which tells the browser the text encoding. The charset parameter only applies to text/* and a few others; it is meaningless on image/png.

Servers decide the type in one of three ways: a static mapping from extension to type (Apache's mime.types, nginx's types block), an explicit header set by your application code, or a guess from the first bytes of the file (content sniffing). The tool on this page reproduces the first of those: the extension-to-type mapping every server ships with.

The extension and the header can disagree. If you rename photo.png to photo.jpg but the server still sends Content-Type: image/png, the browser trusts the header and treats it as PNG. Fix the header, not just the name.

How the tool maps both directions

The mapping is many-to-one in one direction and one-to-many in the other. One MIME type can own several extensions, but a well-behaved server picks a single type for each extension.

Count the JPEG case. The type image/jpeg is registered for four common extensions: .jpg, .jpeg, .jpe and .jfif. Go the other way and each of those four extensions resolves back to exactly one type, image/jpeg. So the extension-to-type direction is a function (one input, one output), while the type-to-extension direction returns a set.

Direction and cardinality of the lookup
You enterYou get backCount for JPEG
Extension .jpgOne MIME type1
Extension .jpegOne MIME type1
MIME type image/jpegA set of extensions4

Reading a type: the structure of the subtype

The type (the part before the slash) is one of a small fixed list: text, image, audio, video, font, application, model, multipart and message. The subtype carries the detail, and it often has structure of its own.

Tree prefixes
vnd. marks a vendor format, as in application/vnd.ms-excel. x. once marked unregistered experiments; new code should avoid it.
Structured suffixes
A + suffix names the underlying syntax. image/svg+xml is SVG built on XML; application/manifest+json is a manifest built on JSON. RFC 6839 defines these suffixes so generic parsers know the base format.
The catch-all
application/octet-stream means "unknown binary". A browser that receives it will download the file rather than display it, which is exactly why serving a stylesheet or font as octet-stream fails silently.

A worked example you can reproduce

Looking up the defaults

Load the tool and press Look up with the field defaults. Follow the resolution the same way a server does.

  1. Take the extension css. Strip any leading dot and lowercase it, so .CSS and css both normalize to css.
  2. Find css in the extension table. It maps to exactly one type: text/css.
  3. Now reverse it. Enter text/css. The type-to-extension direction returns the set { css }, size 1, because no other extension claims that type.
  4. Compare with image/jpeg, which returns { jpg, jpeg, jpe, jfif }, size 4. Same mechanism, larger set.

The round trip for css is lossless: extension to type to extension gives back css. The round trip for jpeg is not, because jpeg → image/jpeg → jpg collapses to the primary extension.

Most types own one extension. image/jpeg owns four. application/octet-stream owns none, because it is the fallback for anything unrecognized.

Pick a served Content-Type for a file and see whether the browser renders it, downloads it, or blocks it. A stylesheet served as text/css applies; served as text/plain it is ignored; served as application/octet-stream it downloads.

The types browsers treat specially

For most files a slightly wrong type is harmless: the browser sniffs the bytes and displays the file anyway. For a few contexts the browser refuses to guess, because guessing wrong would be a security hole. When you send X-Content-Type-Options: nosniff (which large sites do by default), these rules apply strictly:

  • Stylesheets require text/css. Any other type is dropped.
  • ES modules loaded with <script type="module"> require a JavaScript type: text/javascript, application/javascript or the application/ecmascript family. A module served as text/plain fails to execute.
  • Fonts use font/woff2, font/woff, font/ttf and font/otf, standardized in RFC 8081. Older servers send application/font-woff; that still works, but the font/* forms are current.
  • SVG used as an image needs image/svg+xml. Served as text/plain it shows as text, not a picture.

If a resource "works locally but not in production", check the response header in your browser's network panel before you touch the code. A CDN or a misconfigured static host is the usual culprit, and the fix is one line in the server config.

Common mistakes

Four errors account for most MIME problems in practice.

  1. Trusting the extension in code. A file named invoice.pdf can contain anything. If you accept uploads, validate the actual bytes (the magic number), not the name. A real PDF starts with the four bytes 25 50 44 46 (%PDF).
  2. Serving JSON as text. application/json is the registered type (RFC 8259). Sending text/plain works for humans reading it but can defeat client libraries that switch on the type.
  3. Forgetting charset on text. Without ; charset=utf-8 on a text/html response, some browsers fall back to a legacy encoding and mangle non-ASCII characters.
  4. Adding a charset to binary. image/png; charset=utf-8 is nonsense. The parameter is ignored at best and looks like a bug at worst.

Related tools

MIME types sit next to several other web fundamentals. When the browser rejects a resource, the failing request often carries a telling status: the HTTP status codes reference explains each one. To inspect the URL that fetched the resource, use the URL parser and query editor. When a font or image type problem is really a rendering problem, the CSS gradient, shadow and radius generator and the color converter and contrast checker help you rebuild the visual without hunting for a broken asset. To see which browser is enforcing strict MIME checks, decode the request with the user-agent parser.

Frequently asked questions

Is MIME type the same as file extension?

No. The extension lives in the file name on disk; the MIME type is a label sent in the Content-Type header over the network. A server maps one to the other, but a browser only ever sees the header. That is why renaming a file does not fix a type problem.

Why does my CSS load but not apply?

The server is almost certainly sending the wrong type. A strict browser applies a linked stylesheet only when its response type is text/css. Check the network panel; if you see text/plain or application/octet-stream, fix the server mapping.

What does application/octet-stream mean?

It means "unknown binary". The browser has no format to display, so it downloads the file instead. Seeing it on an asset you expected to render is a sign the server has no mapping for that extension.

Should I use text/javascript or application/javascript?

Both work. The WHATWG HTML standard now recommends text/javascript as the canonical type for scripts, and it is the type most servers send. application/javascript is still accepted everywhere.

Does this tool send my file anywhere?

No. The lookup runs entirely in your browser against a built-in table. Nothing you type leaves your device.