JSON vs JSON5
JSON5 adds back the conveniences JSON deliberately removed. That makes it better for configuration and worse for everything else.
The Problem JSON5 Solves
JSON was designed for machines to exchange, and its strictness serves that purpose well. But it steadily leaked into a job it was not designed for: configuration files that humans write and maintain. There, the missing conveniences hurt.
You cannot explain why a setting exists, because there are no comments. You cannot reorder a list without adjusting commas, because trailing commas are forbidden. And you must quote every key, even when the keys are plain identifiers.
JSON5 is a superset that restores those conveniences, borrowing from ES5 syntax. The same file, in both formats:
// JSON — valid, but nothing explains itself
{
"port": 8080,
"timeoutMs": 30000,
"replicas": ["db-r1", "db-r2"]
}// JSON5 — annotated and easier to edit
{
port: 8080, // unquoted key, and a comment
timeoutMs: 30_000, // numeric separator for readability
/* Read replicas. Order matters: the first is preferred. */
replicas: [
'db-r1', // single quotes are fine
'db-r2', // trailing comma is fine
],
}What JSON5 Adds
| Feature | JSON | JSON5 |
|---|---|---|
| Comments | No | Yes — line and block |
| Trailing commas | No | Yes |
| Unquoted keys | No | Yes, for valid identifiers |
| Single-quoted strings | No | Yes |
| Multi-line strings | No | Yes, via line continuation |
| Hexadecimal numbers | No | Yes — 0xFF |
| Leading / trailing decimal point | No | Yes — .5 and 5. |
| Infinity and NaN | No | Yes |
| Explicit plus sign | No | Yes — +1 |
Note that several of these are exactly the mistakes listed on the common JSON errors page. That is not a coincidence — people write trailing commas and unquoted keys in JSON precisely because those are legal everywhere else they type, and JSON5 accepts the habit rather than fighting it.
The Superset Direction Matters
JSON5 is a strict superset of JSON, and the asymmetry is the whole practical story:
Every JSON document → parses as JSON5 ✓
A JSON5 document using
its added features → parses as JSON ✗So a JSON5 parser can read your existing JSON files unchanged, but the moment you use a comment or a trailing comma, that file is no longer readable by anything expecting JSON — which is every browser, every standard library, and every tool you did not specifically configure.
This is why JSON5 has stayed a configuration format rather than an interchange one. Its adoption cost is not the syntax; it is that every consumer needs a non-standard parser.
JSONC: The Smaller Middle Ground
JSONC — "JSON with Comments" — adds only comments and trailing commas, and nothing else. It is far more widely deployed than JSON5, largely because Microsoft uses it:
// tsconfig.json is JSONC, despite the .json extension
{
"compilerOptions": {
// Target modern runtimes; we do not support IE
"target": "ES2022",
"strict": true, // trailing comma is tolerated here
}
}This explains a genuinely confusing situation: tsconfig.json, .vscode/settings.json and launch.json all accept comments, while the same syntax in package.json breaks npm. The extension is identical; the parser is not. If a JSON file in your project tolerates comments, it is JSONC and something specific is reading it.
JSONC is the more conservative choice of the two. It fixes the two things that actually hurt in configuration files and leaves JSON's other rules alone, so a document is easier to convert back if you need to.
Using JSON5
npm install json5import JSON5 from "json5";
// Mirrors the built-in JSON API
const config = JSON5.parse(text);
const output = JSON5.stringify(config, null, 2);
// Reading a .json5 config file
import { readFileSync } from "node:fs";
const config = JSON5.parse(readFileSync("config.json5", "utf8"));Give JSON5 files a .json5 extension. Naming one .json is asking for trouble — any generic tool that opens it will fail, and the error will not obviously point at the file format.
Parsers exist for Python (json5), Go, Rust and others, but none is in a standard library. That dependency is the real cost of adopting the format.
Getting Comments Without Leaving JSON
If you only want to annotate a config file and would rather not add a parser, two approaches work in plain JSON.
A comment key — legitimate JSON, since it is just a string value:
{
"_comment": "Timeout is 30s to match the upstream gateway.",
"timeoutMs": 30000
}Or point at a schema, which puts the documentation somewhere better than a comment and gives you editor autocomplete and validation at the same time:
{
"$schema": "https://example.com/schemas/app-config.json",
"timeoutMs": 30000
}The schema approach is usually the better answer. Descriptions live with the field definitions, editors surface them on hover, and invalid values are flagged as you type — none of which a comment does.
Choosing
JSON
Anything crossing a network, anything a program generates, anything a third party consumes. The default, and correctly so.
JSONC
Project configuration where comments would help and your toolchain already supports it — TypeScript and VS Code files especially.
JSON5
Hand-maintained config where the extra syntax genuinely earns its dependency. Consider whether YAML or TOML fits better first.
One rule regardless of choice: never emit JSON5 or JSONC from an API. Consumers expect application/json, and a response containing a comment will fail in every standard client with an error that gives no hint of the real cause.
Frequently Asked Questions
Is JSON5 valid JSON?
No, and the direction matters. JSON5 is a superset, so every JSON document is valid JSON5 — but a JSON5 document using comments, trailing commas or unquoted keys will be rejected by a standard JSON parser.
What is the difference between JSON5 and JSONC?
JSONC is 'JSON with Comments' — it adds only comments and trailing commas, and is what VS Code uses for settings.json and tsconfig.json. JSON5 goes considerably further, adding unquoted keys, single quotes, hexadecimal numbers, multi-line strings and more.
Can I use JSON5 for an API?
You should not. Consumers expect application/json, and no browser or standard library parses JSON5 natively, so every client would need an extra dependency. JSON5 is for files humans edit, not for data crossing a network.
Why does my tsconfig.json allow comments when JSON does not?
Because tsconfig.json is JSONC rather than JSON, despite the extension. The TypeScript compiler and VS Code use a parser that tolerates comments and trailing commas. A generic JSON parser reading the same file will fail.