Utilo

JSON MIME Type – Free, Online, Private

application/json is the IANA type for a JSON text, and the header does not take a charset parameter.

What .json is

A .json file is a JSON text: one value, UTF-8, with no comments and no trailing commas. Objects and arrays are the values APIs return. RFC 8259 requires UTF-8 for data exchanged outside a closed system. The first two bytes are often 7B for an object or 5B for an array. A UTF-8 BOM is legal in the Unicode sense and rejected by a lot of parsers, so do not write one. Source maps use the same type and the extension .map. That is a different file, and this page is the .json spelling.

IANA registers application/json in RFC 8259. The media type is application/json. Extensions that use it on this page: .json. 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 application/json

What sends application/json: API responses, static JSON files, and package manifests should send application/json on the response that carries the body. Fetch and XHR use the header to decide whether response.json() is appropriate. A browser will not execute a JSON response as a script when the type is application/json, which is the defense against a JSON hijack that depended on the old browser habit of sniffing. X-Content-Type-Options: nosniff keeps a proxy from undoing that. Do not send text/json or application/x-javascript. Neither is the registered type. The file on disk is still .json. Once the response exists, a client trusts application/json, not the filename. Express res.json() sets application/json and serializes the value. If you build the bytes yourself, set the header before the first write. nginx will add the type for a file ending in .json only when mime.types lists it. A default build usually does. An API behind that file server should still set the header in the application, because a rewritten URL may not end in .json.

Content-Type for .json

Send application/json 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: application/json

nginx, Apache, and Express

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

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

Pitfalls for application/json

Pitfalls that show up for application/json, and not for a neighboring type with a similar extension: The charset parameter is the bug people add while trying to be careful. RFC 8259 says no charset parameter is defined for this registration and that adding one has no effect on a compliant recipient. Some older parsers reject the request or the response when they see charset=utf-8. Send the type alone. The body is UTF-8 because the format says so, not because the header repeated it. A second trap is returning JSON with a 200 status and an error object. The type describes the body. The status describes the outcome.

  • Comments and trailing commas are not JSON. A file that needs them is JSONC or JSON5, and application/json is the wrong promise.
  • Content-Encoding: gzip compresses the representation. It does not change the type. The header stays application/json.
  • A UTF-8 BOM in front of { makes JSON.parse throw in most libraries. Strip it before you publish the file.
  • Serving a .json URL as text/html lets the browser parse it as a document if the body contains markup. nosniff closes that.

Frequently asked questions

Should I send charset=utf-8 on JSON?

No. RFC 8259 does not define a charset parameter for application/json. The text is UTF-8. Extra parameters have broken older parsers.

Is text/json acceptable?

No. The registered type is application/json. text/json is a leftover that some clients do not treat as JSON.

Can a browser run a JSON response as JavaScript?

Not when the Content-Type is application/json and sniffing is disabled. That separation is the point of the type.

Does .map use this type?

A source map is JSON and is commonly served as application/json. The extension is .map, which this page does not claim, because .map is also used for other files.