Utilo

JS MIME Type – Free, Online, Private

text/javascript is the standard type for a JavaScript file. RFC 9239 obsoletes application/javascript, and you do not send a charset parameter.

What .js is

A .js file is JavaScript source. RFC 9239 makes text/javascript the type for it and obsoletes application/javascript, application/x-javascript, and the various text/javascript1.x aliases. The source is UTF-8. The RFC does not want a charset parameter. Browsers use UTF-8 for classic scripts and modules. A BOM is tolerated and is still a bad idea. The file is not JSON, even when it consists of an expression. A script is executed. JSON is parsed. The type is how a browser tells those apart when a URL is loaded as a script.

IANA registers text/javascript in RFC 9239, which obsoletes application/javascript. The media type is text/javascript. Extensions that use it on this page: .js. 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/javascript

What sends text/javascript: Send text/javascript for a classic script and for a module file you serve as .js. The module versus classic distinction is the script element's type attribute or the import, not a different MIME type. A wrong type, such as text/plain, makes the browser refuse the script when nosniff is on, which you want for user content and which will also break your bundle if you mislabel it. Do not send application/javascript on a new server. Update the old mime.types line. Source maps stay application/json and are referenced by a comment, not by changing this type. The file on disk is still .js. Once the response exists, a client trusts text/javascript, not the filename. Workers and classic scripts both use this type. The worker constructor checks it. A CDN that adds a default download disposition to unknown types will prevent execution. .js has to be configured, not left to fall through to application/octet-stream.

Content-Type for .js

Send text/javascript with no charset parameter. The registration either defines no charset parameter or tells clients to ignore one, and the payload is UTF-8 by rule rather than by a parameter. Adding charset=utf-8 looks helpful and has broken strict parsers.

Content-TypeContent-Type: text/javascript

nginx, Apache, and Express

These snippets map .js to text/javascript. 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 .js 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/javascript             js;
ApacheAddType text/javascript .js
Expressimport express from "express";

const app = express();
app.use(express.static("public", {
  setHeaders(res, filePath) {
    if (filePath.endsWith(".js")) {
      res.setHeader("Content-Type", "text/javascript");
    }
  },
}));

Pitfalls for text/javascript

Pitfalls that show up for text/javascript, and not for a neighboring type with a similar extension: Serving a .js URL as text/html is an XSS bug if the body can contain user text and a browser ever treats it as a document. nosniff plus the correct type closes the sniffing path. It does not make the script safe to execute. Another trap is a charset parameter. RFC 9239's registration is UTF-8, and a parameter that names another encoding is a lie. Another is a service worker registered from a script that was served without a JavaScript type. Registration fails. A fourth is caching a personalized script on a public URL. Fingerprint the file or mark it private.

  • application/javascript is obsolete. Send text/javascript.
  • text/js and application/x-javascript are not the standard type.
  • A JSON file served as text/javascript will execute if it is valid script. Do not do that to make an old API 'easy'.
  • Import maps are application/importmap+json when they are external. They are not text/javascript.

Frequently asked questions

Is application/javascript still correct?

It is obsolete. RFC 9239 says to send text/javascript.

Do I add charset=utf-8?

No. JavaScript source is UTF-8 by RFC 9239. Omit the charset parameter.

Is a module a different MIME type?

No. Modules and classic scripts are both text/javascript. The script tag or the import decides how the file is evaluated.

What does nosniff change?

The browser will not execute the response unless the type is a JavaScript type. A wrong mapping then breaks the page, which is better than sniffing HTML into a script.