MIME Types Guide: Content-Type Header, Sniffing, and Vendor Types
Every HTTP response that carries a body includes a Content-Type header. That single header tells the browser, the CDN, and your API client what the bytes actually are — whether to render them as a web page, parse them as JSON, play them as video, or prompt the user to save a file. Getting it wrong breaks rendering, triggers security warnings, and can cause CORS preflight failures. Use the MIME Types Reference to look up any type as you read.
MIME Anatomy: type/subtype[; parameter]
A MIME type (Multipurpose Internet Mail Extensions type) has two required parts and one optional part:
type/subtype[; parameter=value]
# Examples
text/html; charset=utf-8
application/json
image/png
application/vnd.api+json; charset=utf-8The type is a broad category. The subtype is the specific format within that category. The optional parameter adds extra metadata — most commonly a charset declaration. The IANA (Internet Assigned Numbers Authority) maintains the official registry of registered MIME types at https://www.iana.org/assignments/media-types/. Any type not in that registry is unofficial, though vendors routinely use unregistered types in practice.
Top-Level Types
There are nine standardized top-level types. Understanding them immediately narrows down what a type means before you even read the subtype:
| Type | Meaning | Examples |
|---|---|---|
| text | Human-readable text | text/html, text/plain, text/css |
| image | Still images | image/png, image/jpeg, image/webp |
| video | Video media | video/mp4, video/webm |
| audio | Audio media | audio/mpeg, audio/ogg |
| application | Binary or application-specific data | application/json, application/pdf |
| multipart | Multiple parts with different types | multipart/form-data, multipart/mixed |
| message | Email message encapsulation | message/rfc822 |
| font | Font files | font/woff2, font/ttf |
| model | 3D model data | model/gltf+json, model/obj |
Common MIME Types
These are the types you encounter on almost every web project. Knowing them by heart prevents misconfiguration in nginx, Apache, Express, and CDN cache rules.
| Format | MIME Type | Notes |
|---|---|---|
| HTML | text/html; charset=utf-8 | Always include charset for HTML |
| JSON | application/json | UTF-8 is the default per RFC 8259 |
| XML | application/xml | text/xml also valid but legacy |
application/pdf | Browser may render inline or download | |
| JPEG | image/jpeg | image/jpg is not an IANA type |
| PNG | image/png | |
| WebP | image/webp | |
| SVG | image/svg+xml | Structured suffix +xml |
| MP4 | video/mp4 | |
| CSV | text/csv | Excel ignores this — see pitfalls |
| JavaScript | text/javascript | application/javascript is obsolete per RFC 9239 |
| CSS | text/css | |
| WebAssembly | application/wasm | Required for streaming compilation |
| WOFF2 | font/woff2 |
Charset Parameter
The charset parameter declares the character encoding of text content:
Content-Type: text/html; charset=utf-8
Content-Type: text/plain; charset=iso-8859-1
Content-Type: text/csv; charset=utf-8For text/* types, always declare charset=utf-8 explicitly. Without it, some older parsers default to ISO-8859-1, which breaks any non-ASCII content including curly quotes, em dashes, and accented characters.
JSON is a notable exception. RFC 8259 mandates UTF-8 as the only permitted encoding for JSON exchanged between systems that are not part of a closed ecosystem. Sending charset=utf-8 alongside application/json is harmless but redundant — the charset is already implicit. You will still see it in the wild:
# Both are acceptable for JSON responses
Content-Type: application/json
Content-Type: application/json; charset=utf-8Vendor-Specific Types
The vnd. prefix (vendor) indicates a format specific to a company or product. These are registered with IANA but defined by the vendor, not a standards body. You encounter them constantly in enterprise APIs and Microsoft Office files:
| MIME Type | Format |
|---|---|
application/vnd.api+json | JSON:API specification responses |
application/vnd.ms-excel | Legacy Excel (.xls) |
application/vnd.openxmlformats-officedocument.spreadsheetml.sheet | Modern Excel (.xlsx) |
application/vnd.openxmlformats-officedocument.wordprocessingml.document | Word document (.docx) |
application/vnd.openxmlformats-officedocument.presentationml.presentation | PowerPoint (.pptx) |
application/vnd.google-apps.document | Google Docs internal format |
application/vnd.docusign+json | DocuSign envelope JSON |
The application/vnd.api+json type is worth calling out specifically. JSON:API is a specification for structuring API request and response payloads. When a server returns this type, the client knows the body follows JSON:API conventions — top-level data, errors, and meta keys, relationship links, and so on. Setting the wrong type here (application/json instead of application/vnd.api+json) breaks content negotiation for strict JSON:API clients.
Structured Suffixes
Structured suffixes communicate the underlying serialization format independently of the specific type. The suffix comes after a + in the subtype:
image/svg+xml # SVG is XML
application/vnd.api+json # JSON:API is JSON
model/gltf+json # glTF 3D model serialized as JSON
application/atom+xml # Atom feed is XMLThe +json suffix tells parsers they can apply a JSON parser to the body even if they do not specifically understand the full type. Similarly, +xml means a generic XML parser will work. The +zip suffix (used by the Office Open XML formats) signals that the file is a ZIP archive — a .docx is literally a ZIP containing XML files, which is why its MIME type is application/vnd.openxmlformats-officedocument.wordprocessingml.document with the underlying container being a ZIP.
How Browsers Use MIME Types
The Content-Type header is the primary signal browsers use to decide what to do with a response body. The decision tree is roughly:
- text/html — parse as HTML and render the page
- text/css — apply as a stylesheet (only if fetched as a CSS resource)
- text/javascript — execute as JavaScript (only if fetched as a script)
- image/* — decode and display the image
- video/*, audio/* — play in the media player
- application/pdf — render in the built-in PDF viewer (Chrome, Firefox)
- application/octet-stream — generic binary data; always triggers a download
- application/json — display as raw text in the browser, not rendered as HTML
The application/octet-stream type is the safe default for file downloads. If you serve a file with this type, the browser will always prompt to save it regardless of the actual content. Use it when you want a download behavior even for types the browser could otherwise render, such as PDF or SVG.
# Forces download even for HTML content
Content-Type: application/octet-stream
Content-Disposition: attachment; filename="export.html"MIME Sniffing and X-Content-Type-Options: nosniff
Browsers do not always trust the Content-Type header blindly. When the declared type seems wrong or is missing, browsers perform MIME sniffing — they inspect the first bytes of the response body and guess the actual type. This behavior exists for historical compatibility with misconfigured servers.
MIME sniffing creates a security vulnerability. If an attacker uploads a file that begins with HTML but is served with Content-Type: image/png, a sniffing browser may execute it as HTML and run any embedded scripts. This is a variant of cross-site scripting.
The defense is the X-Content-Type-Options: nosniff response header:
X-Content-Type-Options: nosniffWhen nosniff is set, the browser honors the declared Content-Type exactly and refuses to override it. If the type says image/png, the browser treats it as an image — it will not sniff the body and re-classify it as HTML. The consequence is that a wrong Content-Type will cause the resource to fail to load rather than silently work due to sniffing.
Beyond script injection, nosniff also prevents browsers from loading cross-origin responses as a different resource type than declared, which closes off certain side-channel information leaks. Every application should set this header on all responses.
# Correct combination for a JSON API
Content-Type: application/json
X-Content-Type-Options: nosniff
# Correct combination for an HTML page
Content-Type: text/html; charset=utf-8
X-Content-Type-Options: nosniffContent-Disposition
While Content-Type says what the data is, Content-Disposition says how it should be presented. The two values are inline (default, display in browser) and attachment (download):
# Display in browser if possible
Content-Disposition: inline
# Trigger download with suggested filename
Content-Disposition: attachment; filename="report-2026-04.csv"
# UTF-8 encoded filename (RFC 5987)
Content-Disposition: attachment; filename*=UTF-8''rapport-%C3%A0-t%C3%A9l%C3%A9charger.csvFilenames with non-ASCII characters require RFC 5987 encoding using the filename* parameter (note the asterisk). The format is charset'language'percent-encoded-value. For broad compatibility, include both filename (ASCII fallback) and filename* (UTF-8):
Content-Disposition: attachment; filename="download.pdf"; filename*=UTF-8''t%C3%A9l%C3%A9chargement.pdfCommon Pitfalls
Several real-world problems stem directly from incorrect MIME handling:
- Wrong Content-Type breaks CORS preflight. When a browser sends a cross-origin POST with
Content-Type: application/json, it triggers a preflight OPTIONS request. If the server is not configured to handle OPTIONS or the declared type does not match what the server expects, the preflight fails and the actual request is never sent. The fix is ensuring the server explicitly allows the content type in itsAccess-Control-Allow-Headersresponse. - Excel ignores MIME types. Serving a CSV file with
Content-Type: text/csvdoes not make Excel open it correctly — Excel uses file extension, not MIME type, for format detection. When generating Excel-targeted downloads, useapplication/vnd.openxmlformats-officedocument.spreadsheetml.sheetand produce a real.xlsxfile, not a renamed CSV. - Email attachments use different rules. Email clients (Outlook, Gmail) rely on MIME types in
multipart/mixedmessages to determine how to render attachments. An attachment served asapplication/octet-streammay be blocked by mail security filters. Use specific types likeapplication/pdfwhen possible. - Server default MIME maps are incomplete. Web servers like nginx and Apache ship with a
mime.typesfile that maps file extensions to MIME types. This file often omits newer formats:.webp,.wasm,.woff2, and.avifmay need to be added explicitly. Missing entries cause the server to fall back toapplication/octet-stream, which prevents browsers from rendering the resource correctly. image/jpgis not a valid MIME type. The correct type isimage/jpeg. Hardcodingimage/jpgin server config or application code causes type mismatches that surface as broken images in strict clients.- WebAssembly requires the exact type. Browsers only enable streaming compilation (
WebAssembly.instantiateStreaming) when the response carriesapplication/wasmexactly. Any other type — includingapplication/octet-stream— forces the slower non-streaming path and may trigger a console warning.
Look up the correct MIME type for any file format in the MIME Types Reference. Related reading: HTTP Status Codes Guide and Web Payload Workflow.