JSON Comments: Why They Don't Exist and How to Add Them Anyway (JSONC, JSON5, Workarounds)
JSON has no comment syntax — but your config files need them. This guide explains JSONC, JSON5, and four practical workarounds so you can annotate JSON without breaking parsers.
Have broken JSON right now? Fix it free in under 1 second — no signup.
Fix My JSON →If you've ever tried to add a // note: line to a JSON file and watched everything break, you already know the problem. JSON has no comment syntax. Full stop. Not //, not /* */, not #. The spec is explicit: a JSON value is an object, array, string, number, boolean, or null. Comments are none of those.
This guide explains exactly why that's the case, then covers every practical way to annotate JSON anyway — from JSONC and JSON5 to _comment key conventions and strip-and-parse pipelines.
Why JSON Has No Comments
JSON was designed by Douglas Crockford as a minimal data interchange format — a proper subset of JavaScript object literals that could be parsed with a single regular expression. Comments were deliberately excluded.
Crockford later explained his reasoning in a 2012 Google Groups post: he had originally included comments in early JSON drafts, but removed them because he discovered that comments were being used to embed parsing directives — effectively turning JSON into a configuration language with hidden side channels. Removing comments kept the format purely declarative.
The core principle: JSON is a data format, not a configuration format. Data doesn't need annotations. The human reading a JSON API response doesn't need to know why a field is structured that way — the consuming code does.
That design decision made sense for data interchange. It created friction for configuration files, where human context matters.
The Four Real Options
1. JSONC — JSON with Comments
Best for: VS Code configs, TypeScript configs, any tool that explicitly supports it.JSONC (JSON with Comments) is an informal extension of JSON that adds:
- Single-line comments:
// comment - Multi-line comments:
/* comment */ - Trailing commas in objects and arrays
{
// Editor settings
"editor.fontSize": 14,
"editor.tabSize": 2, // 2 spaces, not 4
/* Formatting */
"editor.formatOnSave": true,
"files.autoSave": "onFocusChange",
}
JSONC was introduced by Microsoft for VS Code's configuration files (settings.json, launch.json, tasks.json, tsconfig.json). It is not an official IETF standard — it's a convention with a parser implementation and a spec at jsonc.org.
- Use the
.jsoncextension for files with JSONC-specific syntax - JSONC parsers MUST ignore comments without changing parsed values
- A valid JSON file is also valid JSONC (comments are additive)
- A JSONC file with comments stripped is valid JSON
- VS Code (settings, launch, tasks, keybindings)
- TypeScript (
tsconfig.json,jsconfig.json) - ESLint (
.eslintrc.jsoncwith parser support) - Prettier (
--parser jsonc)
.jsonc files in a pipeline that hands them to JSON.parse() or json.loads() — they will throw.
Parse JSONC in Node.js:
npm install jsonc-parser
import { parse } from 'jsonc-parser';
const raw = `{
// Editor settings
"fontSize": 14, // Display size
"theme": "dark"
}`;
const config = parse(raw);
// { fontSize: 14, theme: 'dark' }
Parse JSONC in Python:
pip install commentjson
import commentjson
with open('settings.jsonc') as f:
config = commentjson.load(f)
2. JSON5 — A More Permissive Superset
Best for: Application config files where you control the parser.JSON5 is a proper specification (json5.org) that extends JSON with:
- Single-line and multi-line comments
- Trailing commas
- Unquoted keys (if valid identifiers)
- Single-quoted strings
- Multiline strings (backslash-escaped newlines)
- Hexadecimal numbers (
0xFF) Infinity,-Infinity,NaN
{
// Database connection
host: "localhost", // unquoted key is valid
port: 5432,
database: 'myapp', // single quotes OK
pool: {
min: 2,
max: 10, // trailing comma OK
},
/*
Legacy flag — remove after migration
to connection pooling v3
*/
legacyMode: false,
}
JSON5 is used by Babel, webpack, and Kelvin.js configs. It has stable parsers for JavaScript, Python, Rust, Go, and most major languages.
Use JSON5 when: You own the config file and the tool that reads it. Don't use it for data exchange across system boundaries.npm install json5
import JSON5 from 'json5';
const config = JSON5.parse(raw);
3. _comment Key Convention
Best for: Strict JSON environments where you can't change the parser.
If you must use standard JSON, you can embed "comments" as string values under a reserved key:
{
"_comment": "Database settings — update these for each environment",
"host": "localhost",
"port": 5432,
"_note_pool": "Increase max to 50 for prod",
"pool": {
"min": 2,
"max": 10
}
}
Variations used in the wild:
"_comment"— most common"//"— used by LGTM config"$schema"— JSON Schema uses this for tooling hints"__comment__"— avoids collision with data keys
- Your code will receive these keys when it parses the object — you must explicitly ignore them
- JSON object keys are technically unordered, so "comment before the thing it describes" is convention, not enforced
- Linters may flag unknown keys if you have strict schema validation
_comment keys in Python:
import json
def strip_comments(obj):
if isinstance(obj, dict):
return {k: strip_comments(v) for k, v in obj.items()
if not k.startswith('_comment')}
if isinstance(obj, list):
return [strip_comments(i) for i in obj]
return obj
with open('config.json') as f:
raw = json.load(f)
config = strip_comments(raw)
4. Strip-and-Parse Pipeline
Best for: CI/CD pipelines, build tools, any automated process that needs comments at the source but clean JSON downstream.Maintain the source file as JSONC (with comments) and strip comments at parse time. This gives you the best of both worlds: human-readable annotated source, machine-readable output.
Usingjq to strip JSONC comments:
Standard jq doesn't understand JSONC. Use a pre-processor first:
# Using the `json-minify` npm package
npx json-minify config.jsonc | jq .
In a Makefile:
build/config.json: src/config.jsonc
npx json-minify $< > $@
Python pipeline using strip-comments:
pip install strip-hints # or: pip install commentjson
import commentjson
import json
with open('config.jsonc') as f:
config = commentjson.load(f)
# Write clean JSON for downstream use
with open('build/config.json', 'w') as f:
json.dump(config, f)
When to use this: When you have a build step anyway. Check JSONC syntax in CI, strip for production artifacts.
Comparison Table
| Approach | Comments | Trailing Commas | Strict JSON? | Parser Required |
|---|---|---|---|---|
| JSONC | // /* */ | ✅ | ❌ | Yes (jsonc-parser) |
| JSON5 | // /* */ | ✅ | ❌ | Yes (json5) |
_comment keys | String values only | ❌ | ✅ | No |
| Strip-and-parse | Any (in source) | Depends | ✅ (output) | Pre-processor |
| Standard JSON | ❌ | ❌ | ✅ | No |
Common Mistakes
Mistake 1: Using JSONC in a JSON.parse() call
// ❌ This will throw SyntaxError
const config = JSON.parse(fs.readFileSync('config.jsonc', 'utf8'));
// ✅ Use jsonc-parser instead
import { parse } from 'jsonc-parser';
const config = parse(fs.readFileSync('config.jsonc', 'utf8'));
Mistake 2: Using .json extension for files with comments
A file with comment syntax should use .jsonc or .json5. Using .json for a file that contains // comments signals that it is standard JSON — tools and linters will fail when they try to parse it.
Mistake 3: Using JSONC for API responses
If a client is fetching JSON from your API, they will use JSON.parse(). Do not return JSONC. Comments have no place in wire format.
Mistake 4: Forgetting that tsconfig.json is JSONC
TypeScript's tsconfig.json has always supported // comments — but that doesn't mean JSON.parse(tsconfig) will work. TypeScript uses its own JSONC-aware parser. If you're reading a tsconfig file programmatically, use the TypeScript compiler API or a JSONC parser, not raw JSON.parse.
What About JSON Schema's $comment?
JSON Schema (draft 7 and later) defines a $comment keyword for schema authors to annotate schemas. It has no semantic meaning — validators MUST ignore it:
{
"$schema": "https://json-schema.org/draft/2020-12",
"$comment": "User profile schema — v2.1. Legacy 'username' field removed.",
"type": "object",
"properties": {
"email": {
"$comment": "Must be verified before granting access",
"type": "string",
"format": "email"
}
}
}
This is safe to use in any JSON Schema validator. The comment travels with the schema, which is useful for teams maintaining schemas over time.
Quick Decision Guide
Using VS Code config files? → Use JSONC (// comments work natively)
TypeScript project config? → JSONC is built in to tsconfig.json
Application config that you control end-to-end? → JSON5 gives you the most flexibility
Need strict JSON compatibility? → Use _comment keys and strip them programmatically
CI/CD pipeline? → Maintain source as JSONC, strip to clean JSON in your build step
API wire format? → No comments. Ever. Use strict JSON.
When JSON Breaks Anyway
Even when you're using strict JSON without comments, parsing can still fail — malformed strings, trailing commas left in by mistake, LLM-generated JSON that includes // comments because the model was trained on JavaScript. If you're dealing with broken JSON at runtime, AI JSON Medic's repair tool handles all of these cases automatically: it strips illegal comments, removes trailing commas, and fixes other structural errors before validation.
For programmatic use, JSON Medic's validator accepts JSON and JSONC (after comment stripping) and returns structured error locations.
Frequently Asked Questions
Can you add comments to JSON?
No — standard JSON has no comment syntax. The spec (RFC 8259) does not define comments. If you try to add // or /* */ to a .json file, any standard JSON parser will throw a syntax error. Use JSONC (.jsonc extension) or JSON5 if you need comments in configuration files.
What is JSONC?
JSONC (JSON with Comments) is an informal extension of JSON that adds single-line (//) and multi-line (/* */) comments, plus trailing commas. It was popularized by Microsoft for VS Code configuration files (settings.json, tsconfig.json, launch.json). JSONC files require a JSONC-aware parser — they are not compatible with standard JSON.parse().
What is the difference between JSONC and JSON5?
Both extend JSON with comment support. JSONC adds comments and trailing commas only. JSON5 adds those plus unquoted keys, single-quoted strings, multiline strings, hexadecimal numbers, and Infinity/NaN values. JSONC is safer for teams already using JSON because it is a strict superset — any JSONC file with comments stripped is valid JSON. JSON5 is more permissive and may introduce syntax that makes conversion back to JSON non-trivial.
How do I parse JSONC in Python?
Install commentjson (pip install commentjson) and replace json.load() with commentjson.load(). Alternatively, install jsonc-parser and use its JsoncParser.parse() method. Both strip comments before handing the result to Python's standard JSON decoder.
Why did Douglas Crockford remove comments from JSON?
Crockford explained in a 2012 post that he included comments in early JSON drafts but removed them after observing that comments were being used to embed parser directives — turning JSON into a configuration format with hidden control flow. Removing comments kept JSON as a pure data format. If you need a configuration format with comments, he suggested using a format that is explicitly designed for it (like YAML or TOML).
Can I use // comments in tsconfig.json?
Yes. TypeScript's tsconfig.json uses a JSONC-aware parser, so // comments are valid. Do not use JSON.parse() to read tsconfig.json programmatically — use the TypeScript compiler API or a JSONC parser.
Still dealing with broken JSON?
Paste it in and get it fixed in under 1 second — free, no signup, no install. Works with ChatGPT, Claude, n8n, and any AI output.
Fix My JSON Free →Related Articles