Skip to content

MIME Type Reference — JavaScript source

A searchable map of common file extensions to their MIME types - text, image, audio, video, application, font, and multipart. Look up by extension or by type, filter by category, and copy the exact Content-Type string for any format.

This is the JavaScript implementation — the same logic the interactive tool runs, in a shareable, citable form.

/**
 * MIME / Content-Type reference - pure, deterministic data + lookups. No DOM,
 * no React, zero dependencies.
 *
 * Language: JavaScript (ES module).
 * CosmoDev polyglot showcase port of the `mime-types` tool, ported from
 * src/lib/mime-types.ts. Display source - part of CosmoDev's polyglot tool
 * pages.
 *
 * A curated set of common file extensions mapped to their standard MIME types,
 * grouped by the seven top-level media types (RFC 2046): text, image, audio,
 * video, application, font, and multipart. Each entry's `type` always equals
 * the top-level segment of its own `mime`, so the category filter and the
 * Content-Type never disagree.
 */

/**
 * The seven top-level media types a curated entry can belong to.
 * @typedef {'text'|'image'|'audio'|'video'|'application'|'font'|'multipart'} MimeCategory
 */

/**
 * One curated extension ↔ MIME mapping.
 * @typedef {Object} MimeEntry
 * @property {string} ext       - File extension, lowercase, no leading dot (e.g. `json`).
 * @property {string} mime      - Full MIME / Content-Type string (e.g. `application/json`).
 * @property {MimeCategory} type - Top-level media type - matches `mime`'s first segment.
 * @property {string} name      - Human-readable format name (e.g. `JSON`).
 */

/**
 * Filter options for {@link filter}.
 * @typedef {Object} MimeFilter
 * @property {MimeCategory} [type]  - Constrain to a single top-level category. Omitted = any.
 * @property {string} [query]       - Free text matched case-insensitively against ext/mime/name.
 */

/** Display order of the categories (used by the UI filter). */
export const MIME_CATEGORIES = [
  'text',
  'image',
  'audio',
  'video',
  'application',
  'font',
  'multipart',
];

/**
 * The curated extension ↔ MIME table. One entry is one (extension, type) pair,
 * so a single extension with several MIME types (e.g. `.js`) appears more than
 * once, and a single MIME with several extensions (e.g. `image/jpeg`) appears
 * once per extension. MIME values follow IANA / MDN conventions.
 *
 * @type {MimeEntry[]}
 */
export const MIME = [
  // ── text ────────────────────────────────────────────────────────────────
  { ext: 'txt', mime: 'text/plain', type: 'text', name: 'Plain text' },
  { ext: 'html', mime: 'text/html', type: 'text', name: 'HTML document' },
  { ext: 'htm', mime: 'text/html', type: 'text', name: 'HTML document' },
  { ext: 'xhtml', mime: 'application/xhtml+xml', type: 'application', name: 'XHTML' },
  { ext: 'css', mime: 'text/css', type: 'text', name: 'CSS stylesheet' },
  { ext: 'csv', mime: 'text/csv', type: 'text', name: 'Comma-separated values' },
  { ext: 'xml', mime: 'application/xml', type: 'application', name: 'XML document' },
  { ext: 'js', mime: 'text/javascript', type: 'text', name: 'JavaScript' },
  { ext: 'js', mime: 'application/javascript', type: 'application', name: 'JavaScript (legacy)' },
  { ext: 'mjs', mime: 'text/javascript', type: 'text', name: 'JavaScript module' },
  { ext: 'json', mime: 'application/json', type: 'application', name: 'JSON' },
  { ext: 'md', mime: 'text/markdown', type: 'text', name: 'Markdown' },
  { ext: 'yaml', mime: 'text/yaml', type: 'text', name: 'YAML' },
  { ext: 'yml', mime: 'text/yaml', type: 'text', name: 'YAML' },
  { ext: 'ics', mime: 'text/calendar', type: 'text', name: 'iCalendar' },
  { ext: 'rtf', mime: 'application/rtf', type: 'application', name: 'Rich text' },
  { ext: 'tsv', mime: 'text/tab-separated-values', type: 'text', name: 'Tab-separated values' },

  // ── image ───────────────────────────────────────────────────────────────
  { ext: 'jpg', mime: 'image/jpeg', type: 'image', name: 'JPEG image' },
  { ext: 'jpeg', mime: 'image/jpeg', type: 'image', name: 'JPEG image' },
  { ext: 'png', mime: 'image/png', type: 'image', name: 'PNG image' },
  { ext: 'gif', mime: 'image/gif', type: 'image', name: 'GIF image' },
  { ext: 'webp', mime: 'image/webp', type: 'image', name: 'WebP image' },
  { ext: 'avif', mime: 'image/avif', type: 'image', name: 'AVIF image' },
  { ext: 'svg', mime: 'image/svg+xml', type: 'image', name: 'SVG image' },
  { ext: 'bmp', mime: 'image/bmp', type: 'image', name: 'Bitmap image' },
  { ext: 'ico', mime: 'image/x-icon', type: 'image', name: 'Icon' },
  { ext: 'tif', mime: 'image/tiff', type: 'image', name: 'TIFF image' },
  { ext: 'tiff', mime: 'image/tiff', type: 'image', name: 'TIFF image' },
  { ext: 'heic', mime: 'image/heic', type: 'image', name: 'HEIC image' },

  // ── audio ───────────────────────────────────────────────────────────────
  { ext: 'mp3', mime: 'audio/mpeg', type: 'audio', name: 'MP3 audio' },
  { ext: 'wav', mime: 'audio/wav', type: 'audio', name: 'WAV audio' },
  { ext: 'ogg', mime: 'audio/ogg', type: 'audio', name: 'Ogg audio' },
  { ext: 'oga', mime: 'audio/ogg', type: 'audio', name: 'Ogg audio' },
  { ext: 'flac', mime: 'audio/flac', type: 'audio', name: 'FLAC audio' },
  { ext: 'aac', mime: 'audio/aac', type: 'audio', name: 'AAC audio' },
  { ext: 'm4a', mime: 'audio/mp4', type: 'audio', name: 'M4A audio' },
  { ext: 'weba', mime: 'audio/webm', type: 'audio', name: 'WebM audio' },
  { ext: 'mid', mime: 'audio/midi', type: 'audio', name: 'MIDI' },
  { ext: 'midi', mime: 'audio/midi', type: 'audio', name: 'MIDI' },

  // ── video ───────────────────────────────────────────────────────────────
  { ext: 'mp4', mime: 'video/mp4', type: 'video', name: 'MP4 video' },
  { ext: 'webm', mime: 'video/webm', type: 'video', name: 'WebM video' },
  { ext: 'avi', mime: 'video/x-msvideo', type: 'video', name: 'AVI video' },
  { ext: 'mov', mime: 'video/quicktime', type: 'video', name: 'QuickTime video' },
  { ext: 'mkv', mime: 'video/x-matroska', type: 'video', name: 'Matroska video' },
  { ext: 'mpeg', mime: 'video/mpeg', type: 'video', name: 'MPEG video' },
  { ext: 'mpg', mime: 'video/mpeg', type: 'video', name: 'MPEG video' },
  { ext: 'ogv', mime: 'video/ogg', type: 'video', name: 'Ogg video' },
  { ext: 'm4v', mime: 'video/mp4', type: 'video', name: 'M4V video' },

  // ── application ─────────────────────────────────────────────────────────
  { ext: 'pdf', mime: 'application/pdf', type: 'application', name: 'PDF document' },
  { ext: 'zip', mime: 'application/zip', type: 'application', name: 'ZIP archive' },
  { ext: 'gz', mime: 'application/gzip', type: 'application', name: 'Gzip archive' },
  { ext: 'tar', mime: 'application/x-tar', type: 'application', name: 'Tar archive' },
  { ext: 'rar', mime: 'application/vnd.rar', type: 'application', name: 'RAR archive' },
  { ext: '7z', mime: 'application/x-7z-compressed', type: 'application', name: '7-Zip archive' },
  { ext: 'bin', mime: 'application/octet-stream', type: 'application', name: 'Binary data' },
  { ext: 'exe', mime: 'application/x-msdownload', type: 'application', name: 'Windows executable' },
  { ext: 'jar', mime: 'application/java-archive', type: 'application', name: 'Java archive' },
  { ext: 'wasm', mime: 'application/wasm', type: 'application', name: 'WebAssembly' },
  { ext: 'doc', mime: 'application/msword', type: 'application', name: 'Word document' },
  { ext: 'docx', mime: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', type: 'application', name: 'Word document (OOXML)' },
  { ext: 'xls', mime: 'application/vnd.ms-excel', type: 'application', name: 'Excel spreadsheet' },
  { ext: 'xlsx', mime: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', type: 'application', name: 'Excel spreadsheet (OOXML)' },
  { ext: 'ppt', mime: 'application/vnd.ms-powerpoint', type: 'application', name: 'PowerPoint' },
  { ext: 'pptx', mime: 'application/vnd.openxmlformats-officedocument.presentationml.presentation', type: 'application', name: 'PowerPoint (OOXML)' },

  // ── font ────────────────────────────────────────────────────────────────
  { ext: 'woff', mime: 'font/woff', type: 'font', name: 'WOFF font' },
  { ext: 'woff2', mime: 'font/woff2', type: 'font', name: 'WOFF2 font' },
  { ext: 'ttf', mime: 'font/ttf', type: 'font', name: 'TrueType font' },
  { ext: 'otf', mime: 'font/otf', type: 'font', name: 'OpenType font' },
  { ext: 'eot', mime: 'application/vnd.ms-fontobject', type: 'application', name: 'Embedded OpenType' },

  // ── multipart ───────────────────────────────────────────────────────────
  { ext: 'mht', mime: 'multipart/related', type: 'multipart', name: 'MHTML web archive' },
  { ext: 'mhtml', mime: 'multipart/related', type: 'multipart', name: 'MHTML web archive' },
];

/**
 * Lowercase an extension and drop a leading dot so `.JSON` and `json` match.
 *
 * @param {string} ext - Raw extension from the user.
 * @returns {string} Normalized extension (no whitespace, no leading dot, lowercase).
 */
export function normalizeExt(ext) {
  return ext.trim().toLowerCase().replace(/^\.+/, '');
}

/**
 * Find every entry whose extension matches. The dot is optional and matching is
 * case-insensitive, so `lookupByExt('.js')`, `lookupByExt('JS')`, and
 * `lookupByExt('js')` are equivalent. Returns `[]` for an unknown/empty ext.
 *
 * @param {string} ext - Extension to look up (dot optional, case-insensitive).
 * @returns {MimeEntry[]}
 */
export function lookupByExt(ext) {
  const e = normalizeExt(ext);
  if (!e) return [];
  return MIME.filter((m) => m.ext === e);
}

/**
 * Find every entry whose MIME type matches, case-insensitively (also tolerating
 * surrounding whitespace). One MIME commonly maps to several extensions - e.g.
 * `image/jpeg` → `jpg`, `jpeg` - so all are returned. `[]` for unknown/empty.
 *
 * @param {string} mime - MIME / Content-Type to look up.
 * @returns {MimeEntry[]}
 */
export function lookupByMime(mime) {
  const m = mime.trim().toLowerCase();
  if (!m) return [];
  return MIME.filter((e) => e.mime.toLowerCase() === m);
}

/**
 * Filter the full table by category and/or a free-text query. Omitted options
 * are ignored; an empty query returns the category-filtered set unchanged. An
 * unknown category value yields nothing (it is not silently coerced).
 *
 * @param {MimeFilter} [opts={}] - Optional `{ type?, query? }` constraints.
 * @returns {MimeEntry[]}
 */
export function filter(opts = {}) {
  const q = (opts.query ?? '').trim().toLowerCase();
  return MIME.filter((e) => {
    if (opts.type !== undefined && e.type !== opts.type) return false;
    if (q) {
      return (
        e.ext.toLowerCase().includes(q) ||
        e.mime.toLowerCase().includes(q) ||
        e.name.toLowerCase().includes(q)
      );
    }
    return true;
  });
}

Also available in 13 other languages

Every CosmoDev tool ships its pure logic in TypeScript (web) and Go (CLI), with authored implementations in a dozen-plus languages — the same contract, ported. Compare all languages side by side →