JSON1

Syntax

Can JSON have comments?

No. There is no comment syntax in JSON and there never was β€” the format was specified as a data interchange format, and a comment is a note between people, not data. That answer is short, so the rest of this page is about what to do instead, and which workarounds actually survive contact with a build pipeline.

The short answer

Douglas Crockford, who specified JSON, removed comments deliberately. His stated reason was that people had started putting parsing directives in them, which would have broken interoperability β€” the one property the format exists to have.

So //, /* */, and # are all syntax errors, in every conforming parser, in every language. There is no flag to turn them on because the grammar has no production for them.

What happens if you try

The error is rarely the word "comment", which is why this trips people up. The parser reaches the / where it expected a comma or a closing brace and reports that instead.

The other things people assume are allowed, and are not.
WrittenResult
// note or # noteSyntax error
/* note */Syntax error
{"port": 8080,}Syntax error: trailing comma
{'port': 8080}Syntax error: single quotes
{port: 8080}Syntax error: unquoted key

Input

{
  "port": 8080 // the port
}

Error

Expected ',' or '}' after property value
in JSON at position 17 (line 2 column 16)
Position 17 is the first /. Nothing in the message mentions comments, so the usual reaction is to go looking for a missing comma.

JSON5 and JSONC

Two supersets exist, and the difference between them matters when you pick one. Neither is JSON: a file written in either will be rejected by JSON.parse and by every strict parser.

  • JSONC is JSON plus comments and trailing commas. Nothing else. It is what VS Code uses for settings.json, and what the TypeScript compiler accepts in tsconfig.json β€” which is why comments work there and people conclude, reasonably, that JSON allows them.
  • JSON5 goes considerably further: unquoted keys, single quotes, hex numbers, leading and trailing decimal points, Infinity and NaN, multi-line strings. Closer to a JavaScript object literal than to JSON.
  • Neither has a registered media type. There is no application/json5, so these are file formats for tools you control, not wire formats for an API.
Where each is safe to use.
Config file you ownAPI request or response
JSONYesYes
JSONCIf the reader supports itNo
JSON5If the reader supports itNo

The four workarounds

Ranked by how well they hold up. The first two are fine; the third has a real cost; the fourth is a trap.

  • 1. Use a format that has comments. If the file is configuration a human maintains, YAML and TOML both support # comments as part of the actual grammar. This is the fix, not a workaround β€” a config file has no reason to be JSON.
  • 2. Strip comments before parsing. Standard for JSONC-style config: a small strip pass, then JSON.parse. Use a real JSONC parser rather than a regex, because a regex will happily destroy a // that appears inside a string value such as a URL.
  • 3. A sidecar key. Legal JSON, and sometimes the only option when the file must stay strict. The cost is that it is now data: it ships to clients, appears in diffs of the parsed object, and any schema with additionalProperties: false will reject it.
  • 4. Do not comment out a block by adding a key like `"_disabled"`. The block is still parsed, still present, and the next person will not know which keys the marker was meant to cover. Delete it; the history is in version control.

The sidecar-key approach

{
  "_comment": "port must match the load balancer",
  "port": 8080
}
Valid JSON, and readable. But _comment is now a field in your data, and a strict schema will reject it.

Converting to YAML for the comments

If the goal is a config file a human can annotate, converting the JSON to YAML once and then adding comments by hand is the clean path. Going the other direction is where the loss happens, and it is worth seeing exactly how.

  • Full-line `#` comments are dropped. Correct behaviour: there is nowhere in JSON to put them.
  • A trailing `#` on an unquoted scalar becomes part of the value. host came back as "localhost # trailing comment". YAML's own spec requires a space before an inline comment and treats it as a comment, so this is a limitation of the converter, not of YAML. Quote the value or put the comment on its own line and it round-trips cleanly.
  • So treat the conversion as one-way. Generate YAML from JSON, annotate the YAML, and keep the YAML as the source of truth rather than converting back and forth.

Commented YAML

# the port the server binds to
port: 8080
host: localhost  # trailing comment
features:
  # experimental, off by default
  - search
  - export

Converted to JSON

{
  "port": 8080,
  "host": "localhost  # trailing comment",
  "features": [
    "search",
    "export"
  ]
}
The full-line comments are gone, which is expected β€” JSON cannot hold them. But look at host.

What to do

The decision is really about what the file is for. Data moving between machines does not need comments. A file a person edits does, and that file should not have been JSON.

  • API payloads: no comments, no supersets. Document the fields in a schema or in your API docs, where the reader will actually look.
  • A config read by one tool you control: JSONC if the tool supports it, otherwise strip-then-parse.
  • A config several people edit: move it to YAML or TOML and stop fighting the format.
  • Anything you need to explain in place: if the explanation matters enough to write down, it matters enough to go in a schema description, which tooling can actually show to the reader.