Can JSON Have Comments? JSONC and JSON5
Can JSON have comments? No. The spec has no comment syntax, and every strict parser rejects // and / / outright. Yet your tsconfig.json is full of comments and TypeScript reads it fine, while the same comment in package.json breaks npm install. The difference is that some tools quietly parse a superset of JSON, and the file extension does not tell you which one you are dealing with.
This post covers why comments were left out, the two supersets you will actually meet (JSONC and JSON5), how to parse commented files in Node and Python, and the regex shortcut that corrupts your data.
What strict parsers do with a comment
Here is a small config file with one comment:
Node 22 and Python 3 both refuse it, and both point at the comment:
Neither message says "comment". The parser was expecting a key, found a /, and stopped. If you get this error on a config file, check line and column first. A comment or a trailing comma is the usual cause. The JSON validator shows the same position on the exact line, which is faster than counting characters in a terminal.
Why JSON has no comments
Douglas Crockford removed comments early on because people were putting parsing directives in them, which would have split JSON into dialects that only some parsers understood. His suggested workaround was to write your commented JSON and pipe it through a minifier before handing it to a parser.
That reasoning holds for data. An API response has no business carrying comments, and a format with exactly one way to write each value is why JSON parsers agree with each other. It falls apart for config files, which humans edit and need to explain. That is where the supersets come from.
JSONC vs JSON5
| Feature | JSON | JSONC | JSON5 |
|---|---|---|---|
// and / / comments | no | yes | yes |
| Trailing commas | no | usually | yes |
| Single-quoted strings | no | no | yes |
| Unquoted keys | no | no | yes |
Hex numbers, Infinity, NaN | no | no | yes |
| Multi-line strings | no | no | yes, with \ |
| Where you see it | APIs, package.json | tsconfig.json, VS Code settings, .jsonc files | .json5 files, Babel and some build configs |
JSON5 is a bigger change. It takes most of ES5 object literal syntax, so {port: 8080, host: 'localhost',} is valid. That is pleasant to type and means a JSON5 file can look nothing like JSON.
My recommendation: if your config needs comments, use JSONC. Every value in a JSONC file is still plain JSON, so stripping the comments gives you a file any parser can read. Reach for JSON5 only if the tool you are configuring already expects it.
Parsing JSONC in Node.js
There is no built-in. You have three reasonable options.
jsonc-parser is the parser VS Code itself uses (3.3.1 at the time of writing):
It is fault tolerant, so check the errors array. It will happily return a partial object from a broken file if you do not.
strip-json-comments removes comments and hands you plain JSON text for JSON.parse:
Tested with 5.0.3. It replaces each comment with spaces instead of deleting it, so if JSON.parse fails afterward, the line and column in the error still match your original file. The trailingCommas option exists in recent majors. Version 3.x, which a lot of lockfiles still pin as a transitive dependency, ignores it and leaves the commas in.
json5 parses the full JSON5 grammar, which includes JSONC:
That works on any JSONC file, but it also accepts single quotes and unquoted keys, so typos that a stricter parser would catch get through. Use it for .json5 files, not as a general comment stripper.
Parsing JSONC in Python
The standard library json module has no option for comments. The json5 package from PyPI handles both formats:
Tested with json5 0.17.3. It is pure Python and noticeably slower than json, which only matters if you are parsing large data files. For a config file read once at startup, it does not.
In Go, Tailscale's hujson package does the same job. Call hujson.Standardize on the bytes, then pass the result to encoding/json.
Do not strip comments with a regex
This is the version you will find in a lot of answers and a lot of codebases:
Run it on the config above and look at what happens to the URL:
The // in https:// looks like a comment to the regex, so it deletes the rest of the line, including the closing quote. JSON.parse then fails with Bad control character in string literal, which sends you looking for a bad character that is not there. Glob patterns break too. The block comment pattern turns "src/*/.ts" into "src*.ts", which still parses, so nothing fails and your build silently matches the wrong files.
A regex cannot tell whether // is inside a string. A comment stripper has to scan the text character by character and track string state, which is what the libraries above do. Use one.
Workarounds when the file must stay strict JSON
Some files have to be valid JSON because tools you do not control parse them. package.json is the common case. Your options there:
- Use a
"//"key. npm ignores it, and it is a long-standing convention:"//": "pinned to 4.x until the auth rewrite ships". Other tools reading the file will see it as data, so do not do this in a file that something validates strictly. - Add a
descriptionor$commentin JSON Schema. The$commentkeyword exists for notes to schema maintainers and validators ignore it. If you generate a schema with the JSON Schema generator, that is the right place for field-level documentation. - Switch formats. If you control the reader and the file is mostly human-edited, YAML has had comments from the start. The JSON to YAML converter gives you a starting file, and the YAML vs JSON post covers the tradeoffs.
- Keep a commented source file and generate the strict one. Write
config.jsonc, strip it in a build step, and commit or ship the output.
Strip before you share
The tools that accept comments are the forgiving ones. The thing reading your file next is often not. If you paste a commented tsconfig.json into a bug report, a CI script, or another formatter, expect it to fail. Run it through strip-json-comments first, then check the result in the JSON formatter. If it formats cleanly there, any JSON parser will accept it. For a deeper look at the other errors strict parsers throw, see fixing JSON parse errors.