What a MIME type lookup answers, and what it does not
This is a two-way MIME type lookup: type an extension, a full filename or a URL and you get the media type to send, or paste a media type and you get the extensions that carry it. Every answer comes with the header as you would write it — charset included when the type is textual — plus a flag when the string you pasted is one of the obsolete names that survive in copied server configs. One hundred and twenty extensions are mapped here, chosen because they turn up on real web servers rather than because a registry lists them.
What it cannot tell you is what a file really is. A media type is a claim made by whoever served the
bytes, and a .png suffix is a claim made by whoever named the file. Neither is evidence. If you
need certainty about untrusted input, read the magic bytes; a lookup table is for deciding what to
declare, not for verifying what arrived.
The extension is a hint, the header is the contract
On a local disk the extension does the work: it is how your operating system picks an application.
Over HTTP the extension is almost irrelevant. The browser reads Content-Type, decides between
rendering, downloading and handing the bytes to a decoder, and never looks at the URL to settle it.
That split explains most of the confusion. A file called report.pdf served as text/plain
displays as gibberish in the tab. A file with no extension at all served as application/pdf opens
in the PDF viewer. Static hosts blur the distinction because they derive the header from the
extension, and then the mapping is only as good as the server's own table — which is exactly the
table that goes stale.
Two extensions in this list are worth a second look. .ts maps to video/mp2t, an MPEG transport
stream, so a server guessing by extension will offer your TypeScript sources to a video player.
And .tgz is a double extension where only the final part decides: the type is application/gzip,
because the tar archive is inside the gzip container, not beside it.
text/javascript won, and it took fifteen years
For most of the 2000s and 2010s there were three plausible types for a script:
application/x-javascript, application/javascript and text/javascript. Style guides told you
the text/ one was deprecated. RFC 9239, published in 2022, reversed that: text/javascript is now
the registered type, and application/javascript is obsolete.
Nothing breaks either way, because browsers accept a generous list of JavaScript types. It matters
anyway for two reasons. Linters and security scanners check against the registry, and nosniff
refuses a script served with a type outside that accepted list — so a config that has drifted far
enough will fail loudly rather than quietly.
The same tidying happened to fonts. RFC 8081 created the font/ top-level type in 2017, which is
why font/woff2 is correct today and application/font-woff2 is the line still sitting in
thousands of copied nginx configs.
application/octet-stream is a shrug
application/octet-stream means unknown bytes. It is a fallback, not a description, and it is what
this tool returns when nothing in the table matches. Faced with it, a browser saves the file,
because rendering something you have declined to identify is how vulnerabilities get written.
Seeing it in production usually means one of three things: the server has no mapping for that extension, an object storage bucket applied its default type at upload time, or a proxy stripped the original header. Setting it deliberately is reasonable for a genuine binary download. Setting it by accident is why a customer reports that your image gallery downloads files instead of showing them.
Sniffing, and the header that stops it
When a type looks wrong, browsers historically sniffed: they inspected the leading bytes and
overrode the declared type. Convenient, and a security problem, because a user upload that a server
declares as text/plain can be sniffed into HTML and executed against your origin.
X-Content-Type-Options: nosniff turns that off. Send it on everything, then make sure your types
are right, because with sniffing disabled a wrong type stops being cosmetic. Two rules go with it
for anything users upload: serve from a separate origin, and never serve user files as
image/svg+xml, since SVG is markup that can carry script.
Every extension in the table
| Extension | MIME type | Group |
|---|---|---|
| .html | text/html | Web and text |
| .htm | text/html | Web and text |
| .css | text/css | Web and text |
| .js | text/javascript | Web and text |
| .mjs | text/javascript | Web and text |
| .cjs | text/javascript | Web and text |
| .json | application/json | Web and text |
| .jsonld | application/ld+json | Web and text |
| .map | application/json | Web and text |
| .xml | application/xml | Web and text |
| .xhtml | application/xhtml+xml | Web and text |
| .txt | text/plain | Web and text |
| .md | text/markdown | Web and text |
| .csv | text/csv | Web and text |
| .tsv | text/tab-separated-values | Web and text |
| .ics | text/calendar | Web and text |
| .vcf | text/vcard | Web and text |
| .wasm | application/wasm | Web and text |
| .webmanifest | application/manifest+json | Web and text |
| .rss | application/rss+xml | Web and text |
| .atom | application/atom+xml | Web and text |
| .xsl | application/xslt+xml | Web and text |
| .yaml | application/yaml | Web and text |
| .yml | application/yaml | Web and text |
| .toml | application/toml | Web and text |
| .sql | application/sql | Web and text |
| .png | image/png | Images |
| .jpg | image/jpeg | Images |
| .jpeg | image/jpeg | Images |
| .jpe | image/jpeg | Images |
| .gif | image/gif | Images |
| .webp | image/webp | Images |
| .avif | image/avif | Images |
| .svg | image/svg+xml | Images |
| .ico | image/vnd.microsoft.icon | Images |
| .bmp | image/bmp | Images |
| .tif | image/tiff | Images |
| .tiff | image/tiff | Images |
| .heic | image/heic | Images |
| .heif | image/heif | Images |
| .jxl | image/jxl | Images |
| .apng | image/apng | Images |
| .psd | image/vnd.adobe.photoshop | Images |
| .mp3 | audio/mpeg | Audio |
| .wav | audio/wav | Audio |
| .ogg | audio/ogg | Audio |
| .oga | audio/ogg | Audio |
| .opus | audio/ogg | Audio |
| .m4a | audio/mp4 | Audio |
| .aac | audio/aac | Audio |
| .flac | audio/flac | Audio |
| .weba | audio/webm | Audio |
| .mid | audio/midi | Audio |
| .midi | audio/midi | Audio |
| .mp4 | video/mp4 | Video |
| .m4v | video/mp4 | Video |
| .webm | video/webm | Video |
| .ogv | video/ogg | Video |
| .mov | video/quicktime | Video |
| .avi | video/x-msvideo | Video |
| .mkv | video/x-matroska | Video |
| .mpeg | video/mpeg | Video |
| .mpg | video/mpeg | Video |
| .ts | video/mp2t | Video |
| .3gp | video/3gpp | Video |
| .3g2 | video/3gpp2 | Video |
| .woff | font/woff | Fonts |
| .woff2 | font/woff2 | Fonts |
| .ttf | font/ttf | Fonts |
| .otf | font/otf | Fonts |
| .ttc | font/collection | Fonts |
| .eot | application/vnd.ms-fontobject | Fonts |
| application/pdf | Documents | |
| .doc | application/msword | Documents |
| .docx | application/vnd.openxmlformats-officedocument.wordprocessingml.document | Documents |
| .xls | application/vnd.ms-excel | Documents |
| .xlsx | application/vnd.openxmlformats-officedocument.spreadsheetml.sheet | Documents |
| .ppt | application/vnd.ms-powerpoint | Documents |
| .pptx | application/vnd.openxmlformats-officedocument.presentationml.presentation | Documents |
| .odt | application/vnd.oasis.opendocument.text | Documents |
| .ods | application/vnd.oasis.opendocument.spreadsheet | Documents |
| .odp | application/vnd.oasis.opendocument.presentation | Documents |
| .rtf | application/rtf | Documents |
| .epub | application/epub+zip | Documents |
| .mobi | application/x-mobipocket-ebook | Documents |
| .tex | application/x-tex | Documents |
| .zip | application/zip | Archives |
| .gz | application/gzip | Archives |
| .tgz | application/gzip | Archives |
| .tar | application/x-tar | Archives |
| .bz2 | application/x-bzip2 | Archives |
| .7z | application/x-7z-compressed | Archives |
| .rar | application/vnd.rar | Archives |
| .xz | application/x-xz | Archives |
| .zst | application/zstd | Archives |
| .iso | application/x-iso9660-image | Archives |
| .jar | application/java-archive | Archives |
| .bin | application/octet-stream | Everything else |
| .exe | application/vnd.microsoft.portable-executable | Everything else |
| .msi | application/x-msdownload | Everything else |
| .dmg | application/x-apple-diskimage | Everything else |
| .deb | application/vnd.debian.binary-package | Everything else |
| .rpm | application/x-rpm | Everything else |
| .apk | application/vnd.android.package-archive | Everything else |
| .sh | application/x-sh | Everything else |
| .py | text/x-python | Everything else |
| .php | application/x-httpd-php | Everything else |
| .swf | application/x-shockwave-flash | Everything else |
| .db | application/vnd.sqlite3 | Everything else |
| .sqlite | application/vnd.sqlite3 | Everything else |
| .pem | application/x-pem-file | Everything else |
| .crt | application/x-x509-ca-cert | Everything else |
| .p12 | application/x-pkcs12 | Everything else |
| .log | text/plain | Everything else |
| .srt | application/x-subrip | Everything else |
| .vtt | text/vtt | Everything else |
| .ndjson | application/x-ndjson | Everything else |
| .geojson | application/geo+json | Everything else |
| .gpx | application/gpx+xml | Everything else |
| .kml | application/vnd.google-earth.kml+xml | Everything else |
The names that were never right
None of the strings on the left is the registered name today, and every one of them is somewhere in a configuration file being copied right now. Browsers tolerate all of them, which is precisely why they persist; the cost lands on the next person to inherit the config, and on any validator, gateway or CDN rule that matches types exactly.
| Written | Registered today | Why it matters |
|---|---|---|
| application/x-javascript | text/javascript | Never registered at all. It predates the argument and survives only in old server configs. |
| application/javascript | text/javascript | Obsolete since RFC 9239, which settled fifteen years of disagreement in favour of text/javascript. |
| text/json | application/json | Never existed. JSON is UTF-8 by definition, so it never needed a text type or a charset. |
| text/xml | application/xml | Valid but dangerous: without an explicit charset it defaults to US-ASCII, which quietly mangles UTF-8. |
| image/jpg | image/jpeg | The extension lost a letter in the MS-DOS era; the media type never did. |
| image/x-png | image/png | The experimental name from before PNG was registered in 1996. |
| image/x-icon | image/vnd.microsoft.icon | Accepted everywhere and registered nowhere. Browsers do not care; validators do. |
| audio/mp3 | audio/mpeg | MP3 is layer three of MPEG audio, and the registered type names the container, not the layer. |
| application/x-pdf | application/pdf | The x- prefix meant unregistered, and PDF has been registered since 1993. |
| application/font-woff | font/woff | RFC 8081 created the font top-level type in 2017 and deprecated every application/font-* name. |
| application/font-woff2 | font/woff2 | Same change as WOFF, and the one most often left behind in a copied nginx config. |
| application/x-font-ttf | font/ttf | Superseded by RFC 8081 along with the rest of the x-font family. |
| application/x-zip-compressed | application/zip | A Windows shell invention that leaks into uploads from Explorer. |
| application/x-rar-compressed | application/vnd.rar | RAR was registered under the vendor tree in 2016. |
| application/x-gzip | application/gzip | Registered without the prefix by RFC 6713. |
| text/yaml | application/yaml | YAML had no registered type until RFC 9512 in 2024; text/yaml and application/x-yaml are both improvised. |
| application/csv | text/csv | CSV is text, and RFC 4180 registered it as such. |
| application/x-httpd-php-source | text/plain | Serving PHP source at all is the bug; the type is the least of it. |
Where this fits
A wrong media type usually shows up first as a status code that makes no sense — a 415 on an upload,
or a 406 from content negotiation — and the HTTP status codes reference says
what each of those is really complaining about. When the argument is about the path that produced
the header rather than the header itself, the URL parser splits a request target into
the pieces the server matches on. And when a type arrives attached to an inline payload, the
Base64 encoder and decoder is the quickest way to see what a data: URI
is actually carrying.
The table above is compiled into this page, so the lookup works with the network off. Your input never leaves the tab.