MD MIME Type – Free, Online, Private
text/markdown is the RFC 7763 type for a Markdown file. The default charset is UTF-8, and the body is source, not rendered HTML.
What .md is
Markdown is a plain-text syntax that a processor turns into HTML or another format. The file is the source. It is not the rendered page. RFC 7763 registers text/markdown and allows a variant parameter, such as text/markdown; variant=CommonMark, when you need to say which flavor. The default charset in the registration is UTF-8, unlike the ancient text/* default. Sending charset=utf-8 is still the clear choice. .markdown is the other extension the RFC mentions. This page is .md, which is the extension repositories actually use.
IANA registers text/markdown in RFC 7763. The variant parameter can name a Markdown flavor. The media type is text/markdown. Extensions that use it on this page: .md. A client compares the type, not the filename, once the response has arrived. The filename still matters on disk and in Content-Disposition, which is why a wrong extension and a wrong header are two different bugs.
What sends text/markdown
What sends text/markdown: Send text/markdown; charset=utf-8 for a raw README or a document API that returns source. A browser will usually show it as text, not as a rendered article. If you want the rendered article, convert it and send text/html on a different URL. Do not send text/html for the source or the user will see the tags you did not intend as tags, and a hostile source becomes a page. A variant parameter is optional. Send it when two flavors would produce different HTML from the same bytes and the client selects a processor. The file on disk is still .md. Once the response exists, a client trusts text/markdown, not the filename. If you serve both the source and the HTML, link them. A Link header with rel=alternate can point from one to the other. The source response stays text/markdown. The HTML response stays text/html. A single URL that switches on Accept needs Vary.
Content-Type for .md
Send text/markdown; charset=utf-8. The charset parameter names the encoding of the body. Leaving it off forces the client to guess, and for several text types the registered default is not UTF-8. Do not send a charset on a redirect. The header belongs on the response that contains the bytes.
Content-TypeContent-Type: text/markdown; charset=utf-8
nginx, Apache, and Express
These snippets map .md to text/markdown. nginx reads the types block when it picks a type from the URL's extension. A location that sets default_type, or an application that sets the header itself, overrides that map. Apache AddType applies in the directory context where you put it. The Express static example writes the header for files ending in .md so a stale mime database in the framework cannot disagree with the type on this page.
nginx# /etc/nginx/mime.types, inside the types { } block
text/markdown md;
charset utf-8;
charset_types text/markdown;
ApacheAddType text/markdown .md
AddCharset UTF-8 .md
Expressimport express from "express";
const app = express();
app.use(express.static("public", {
setHeaders(res, filePath) {
if (filePath.endsWith(".md")) {
res.setHeader("Content-Type", "text/markdown; charset=utf-8");
}
},
}));
Pitfalls for text/markdown
Pitfalls that show up for text/markdown, and not for a neighboring type with a similar extension: Rendering untrusted Markdown to HTML without a sanitizer is an XSS bug. The media type of the source does not sanitize the output. Another trap is a relative image URL in the Markdown that was safe in the repository and points somewhere else once you host the file at a new path. Another is treating text/markdown as a signal that the response is safe to innerHTML. It is source. A fourth is a BOM or a UTF-16 export from a desktop editor. Normalize to UTF-8 before you publish.
- text/x-markdown is unofficial. RFC 7763's type is text/markdown.
- The rendered HTML is text/html. Do not label the HTML with the source type or the source with the HTML type.
- A variant value is an identifier, not a promise that you implemented every extension in that flavor.
- Soft line breaks and hard line breaks differ by flavor. The type does not pick a flavor unless you send variant.
Frequently asked questions
Will a browser render Markdown?
Not as a formatted article. text/markdown is source. Convert to HTML and send text/html if you want rendering.
What is the variant parameter?
RFC 7763's optional variant, for example CommonMark, names the flavor. Omit it when you do not need to distinguish flavors.
Is the default charset UTF-8?
Yes, in the text/markdown registration. Sending charset=utf-8 anyway keeps intermediate tools from guessing.
Is .markdown a different type?
No. It is the other extension from the RFC. Both are text/markdown.