What Are MIME Types?

Every time your browser loads a web page, fetches an API response, or downloads a file, it needs to know what kind of data it is receiving. Is it an HTML document that should be rendered? A JSON payload that should be parsed? An image that should be displayed? MIME types are the labeling system that answers this question.

MIME stands for Multipurpose Internet Mail Extensions. The standard was originally designed in 1996 to allow email messages to carry attachments beyond plain text, but it quickly became the universal way to identify content types across the entire web. Today, every HTTP response includes a Content-Type header containing a MIME type that tells the browser exactly how to handle the data it receives.

Without MIME types, browsers would have no reliable way to distinguish between an HTML page and a CSS stylesheet, or between a JPEG image and a ZIP archive. The entire web depends on these small labels being set correctly, and getting them wrong can cause rendering failures, broken downloads, and even security vulnerabilities.

MIME Type Anatomy

A MIME type follows a strict structure: a type, a forward slash, and a subtype. The type describes the broad category of data, while the subtype identifies the specific format within that category.

type/subtype

There are seven standard top-level types defined by IANA (the Internet Assigned Numbers Authority):

Beyond the basic type/subtype structure, MIME types support two important extensions: suffixes and parameters.

A structured syntax suffix is appended with a + sign and indicates the underlying format of the data. For example, application/ld+json tells you this is JSON-LD data. The +json suffix signals that any JSON parser can read it, even if the application does not understand the ld (Linked Data) semantics. Other common suffixes include +xml (as in image/svg+xml) and +zip (as in application/vnd.openxmlformats-officedocument.spreadsheetml.sheet+zip for .xlsx files).

Parameters follow the subtype after a semicolon and provide additional metadata. The most common parameter is charset, which specifies the character encoding:

Content-Type: text/html; charset=utf-8
Content-Type: application/json; charset=utf-8
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxk

The charset=utf-8 parameter is critical for text-based content. Without it, browsers may fall back to legacy encodings and display garbled characters. For JSON, RFC 8259 specifies that UTF-8 is the default encoding, but explicitly setting the charset is still considered best practice.

The Most Important Types for Web Developers

While hundreds of MIME types are registered with IANA, a web developer interacts with a relatively small set on a daily basis. These are the ones you need to know by heart:

MIME Type Used For Key Details
application/json REST APIs, config files Default for modern API communication. Always use this instead of text/json.
application/x-www-form-urlencoded HTML form submissions Default encoding for <form> elements. Keys and values are percent-encoded, spaces become +.
multipart/form-data File uploads Required when a form includes file inputs. Each field is sent as a separate part with its own Content-Type.
text/html Web pages The MIME type for HTML documents. Always pair with charset=utf-8.
text/css Stylesheets Browsers will refuse to apply a stylesheet if the server sends it with the wrong MIME type.
text/javascript JavaScript files The current standard type. application/javascript was used historically but is now obsolete per RFC 9239.

The distinction between application/x-www-form-urlencoded and multipart/form-data trips up many developers. The rule is simple: if your form includes a file input (<input type="file">), you must set enctype="multipart/form-data" on the form element. The URL-encoded format cannot represent binary file data. For forms that only contain text fields, the default URL-encoded format is more efficient because it produces a smaller payload.

// Sending JSON with fetch
fetch('/api/users', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ name: 'Jane', role: 'admin' })
});

// Sending form data with a file
const form = new FormData();
form.append('avatar', fileInput.files[0]);
form.append('username', 'jane');
fetch('/api/upload', { method: 'POST', body: form });
// Note: don't set Content-Type manually — fetch sets it
// with the correct multipart boundary automatically

Content-Type vs Accept Headers

Two HTTP headers work together to manage MIME types in requests and responses, and confusing them is a common source of bugs.

The Content-Type header declares the MIME type of the data in the message body. When you send a POST request with a JSON body, you set Content-Type: application/json to tell the server what format the body is in. When the server sends back a response, it sets Content-Type: text/html or Content-Type: application/json to tell the browser what it is receiving.

The Accept header works in the opposite direction. It is sent by the client to tell the server which MIME types it can understand and which it prefers. This is called content negotiation. The server reads the Accept header and chooses the best format for its response.

// Request
GET /api/users/42 HTTP/1.1
Accept: application/json

// Response
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{"id": 42, "name": "Jane"}

The Accept header supports quality values (q-values) that let the client express preferences. A q-value of 1.0 (the default) means the type is fully preferred, while lower values indicate fallback options:

Accept: application/json, text/html;q=0.9, */*;q=0.8

This tells the server: "I want JSON if possible. If you cannot provide JSON, HTML is acceptable. If neither is available, I will take anything." APIs that support multiple response formats, such as JSON and XML, rely on this mechanism to serve the right content to each client.

A practical rule: Content-Type describes what you are sending. Accept describes what you want back. GET requests typically only need an Accept header (since they have no body). POST and PUT requests usually need both.

MIME Types for File Downloads

When a server needs to send a file for download rather than display, two headers work together: the MIME type in Content-Type and the Content-Disposition header.

The generic MIME type application/octet-stream represents arbitrary binary data. When a browser receives this type, it treats the response as an opaque blob that should be saved rather than rendered. Servers often use this as a catch-all for downloads when the specific file type is unknown or when they want to force a download regardless of type.

HTTP/1.1 200 OK
Content-Type: application/octet-stream
Content-Disposition: attachment; filename="report.xlsx"

The Content-Disposition header controls whether the browser displays the file inline or prompts a download. Setting it to attachment forces a download dialog, while inline tells the browser to display the content if it can. The filename parameter suggests a default name for the saved file.

However, you do not always need to fall back to application/octet-stream. It is better practice to use the correct specific MIME type combined with Content-Disposition: attachment. For example, serving a PDF download should use application/pdf with an attachment disposition, not application/octet-stream. This way, if the user's system can handle the file type, it will open in the correct application.

// Preferred: specific type + attachment
Content-Type: application/pdf
Content-Disposition: attachment; filename="invoice-2026.pdf"

// Also works but less informative
Content-Type: application/octet-stream
Content-Disposition: attachment; filename="invoice-2026.pdf"

For programmatic downloads in JavaScript, you can create object URLs from blobs with explicit MIME types:

const blob = new Blob([csvData], { type: 'text/csv' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'export.csv';
a.click();
URL.revokeObjectURL(url);

Security Implications of Wrong MIME Types

Incorrectly configured MIME types are not just an inconvenience — they are a security vulnerability. The most dangerous issue is MIME sniffing, a behavior where browsers ignore the declared Content-Type and instead inspect the first few bytes of a response to guess the content type.

MIME sniffing was originally introduced to handle misconfigured servers that sent HTML pages with a text/plain Content-Type. The browser would detect that the content looked like HTML and render it as a web page anyway. While helpful for broken servers, this behavior creates a serious attack vector.

Consider this scenario: an attacker uploads a file to your server with a .jpg extension, but the file actually contains JavaScript. Your server stores it and serves it with image/jpeg in the Content-Type header. Without MIME sniffing protection, a browser might inspect the content, detect that it looks like JavaScript, and execute it. This is a stored XSS attack that bypasses your Content-Type controls.

The fix is the X-Content-Type-Options response header with the value nosniff:

X-Content-Type-Options: nosniff

When this header is present, the browser strictly follows the declared Content-Type and will never attempt to guess. If the Content-Type says image/jpeg, the browser will treat it as an image. If the bytes do not actually form a valid JPEG, the browser will show a broken image rather than trying to interpret the content as something else.

This header should be set on every response from your server. It is one of the most important security headers alongside Content-Security-Policy and Strict-Transport-Security. All modern web frameworks and CDNs support it, and most set it by default.

Additional MIME-related security practices include:

New and Emerging MIME Types

The web platform continues to evolve, and new MIME types are being adopted to support modern formats and capabilities.

image/avif is the MIME type for AVIF images, a next-generation format based on the AV1 video codec. AVIF delivers significantly better compression than JPEG and even WebP, producing smaller files at equivalent visual quality. Browser support has reached critical mass, and major CDNs now serve AVIF as the preferred image format when the client supports it via the Accept header.

image/webp was developed by Google as a replacement for JPEG, PNG, and GIF. WebP supports both lossy and lossless compression as well as animation, making it a versatile format. It typically produces files 25-35% smaller than equivalent JPEGs. All modern browsers now support WebP, making it safe for production use without fallbacks.

<picture>
  <source srcset="photo.avif" type="image/avif">
  <source srcset="photo.webp" type="image/webp">
  <img src="photo.jpg" alt="Photo">
</picture>

application/wasm is the MIME type for WebAssembly binary modules. WebAssembly allows languages like Rust, C++, and Go to run in the browser at near-native speed. Servers must serve .wasm files with this exact MIME type — browsers will refuse to compile a WebAssembly module if the Content-Type is wrong. This is one of the strictest MIME type requirements on the web platform.

// Loading a WebAssembly module — requires correct MIME type
const response = await fetch('module.wasm');
const bytes = await response.arrayBuffer();
const { instance } = await WebAssembly.instantiate(bytes);

font/woff2 is the MIME type for WOFF2 (Web Open Font Format 2) font files. WOFF2 uses Brotli compression and produces font files roughly 30% smaller than the original WOFF format. It has replaced WOFF as the standard web font format, and modern web font services like Google Fonts serve WOFF2 exclusively. Older MIME types like application/font-woff2 are deprecated in favor of the font/ top-level type.

When configuring your web server, make sure these newer types are registered. Many older server configurations do not include them by default, which can cause files to be served as application/octet-stream and trigger download prompts instead of proper handling.

Look Up Any MIME Type

Look up any MIME type or file extension instantly with our free lookup tool.

Open MIME Type Lookup

Frequently Asked Questions

What is a MIME type?
A MIME type (Multipurpose Internet Mail Extensions type), also called a media type, is a standardized label that tells browsers and servers what kind of data is being transferred. It follows the format type/subtype, such as text/html for HTML documents or application/json for JSON data.
What is the difference between Content-Type and Accept headers?
The Content-Type header declares the MIME type of the data being sent in the request or response body. The Accept header is sent by the client to tell the server which MIME types it can understand and prefers to receive. Content-Type describes what you are sending; Accept describes what you want back.
What MIME type should I use for JSON APIs?
Use application/json for JSON API requests and responses. Set Content-Type: application/json when sending JSON in a request body, and set Accept: application/json to tell the server you expect a JSON response. Do not use text/json or text/plain for JSON data.
What is MIME sniffing and why is it dangerous?
MIME sniffing is when a browser ignores the declared Content-Type header and instead inspects the content bytes to guess the file type. This can be dangerous because an attacker could upload a file disguised as an image that actually contains executable JavaScript. Setting the X-Content-Type-Options: nosniff header prevents browsers from MIME sniffing.
What is application/octet-stream used for?
application/octet-stream is a generic MIME type for arbitrary binary data. It is commonly used for file downloads when the server does not know or does not want to specify the exact file type. Browsers typically treat this type as a file to be downloaded rather than displayed, especially when paired with the Content-Disposition: attachment header.