← Back to Blog

JSON Comments: Why They Don't Exist & Workarounds

Every developer who has tried to add a comment to a JSON config file has hit the same wall: JSON does not support comments. This is not an oversight - it is a deliberate design decision. Here is the history, the reasoning, and every practical workaround.

The Problem: You Want to Document Your Config

You have a package.json, a CI pipeline configuration, or an API request body. You want to explain why a particular value is set, or note that a field should only be changed in specific circumstances. In YAML, INI, TOML, or most programming languages, you would add a comment. In JSON, you cannot:

// This is INVALID JSON - it will throw a SyntaxError
{
  // Database connection timeout in milliseconds
  "timeout": 5000,
  "retries": 3 /* increase this if flaky network */
}

JSON.parse() will throw SyntaxError: Unexpected token / immediately. Comments simply do not exist in the JSON specification.

Why Douglas Crockford Removed Comments from JSON

JSON was created by Douglas Crockford around 2001, formalizing a data interchange format already being used informally in JavaScript. When asked why JSON has no comments, Crockford explained on a mailing list:

"I removed comments from JSON because I saw people using them to hold parsing directives, a practice which would have destroyed interoperability. I know that the lack of comments makes some people sad, but it shouldn't. Suppose you are using JSON to keep configuration files, which you would like to annotate. Go ahead and insert all the comments you like. Then pipe it through JSMin before handing it to your JSON parser."

The core insight: if comments were allowed, different parsers would handle them differently, and developers would start using them for non-comment purposes - embedding processing instructions, metadata, or even conditional logic. This would fragment the ecosystem and break interoperability, which is JSON's primary value.

Crockford also pointed to a practical solution: strip comments before parsing. This became the approach used by tools like JSMin, and later by the JSONC format.

Workaround 1: JSONC (JSON with Comments)

JSONC is the most widely adopted workaround for config files. It extends JSON syntax to allow // single-line and /* */ block comments. The comments are stripped by a JSONC parser before the JSON is parsed.

// settings.jsonc
{
  // Editor settings
  "editor.fontSize": 14,
  "editor.tabSize": 2, /* spaces, not tabs */

  // Theme
  "workbench.colorTheme": "Default Dark+",

  // Auto-save every 1 second
  "files.autoSaveDelay": 1000
}

JSONC is used by:

  • VS Code - settings.json, keybindings.json, tasks.json, launch.json, extensions.json
  • TypeScript - tsconfig.json uses JSONC (despite the .json extension)
  • Renovate - renovate.json supports comments via the JSONC parser

Key caveat: JSONC files cannot be parsed by standard JSON.parse(). You need a JSONC-aware parser like jsonc-parser (npm) or VS Code's built-in JSONC support. Never rename a JSONC file as .json and feed it to a standard parser.

// Node.js: parse a JSONC file
import { parse } from 'jsonc-parser';
const content = fs.readFileSync('settings.jsonc', 'utf8');
const config = parse(content); // comments are stripped automatically

Workaround 2: JSON5

JSON5 is a more ambitious superset of JSON. In addition to comments, it adds:

  • Single-line comments (// ...) and block comments (/* ... */)
  • Trailing commas in objects and arrays
  • Unquoted keys (if they are valid identifiers)
  • Single-quoted strings
  • Multi-line strings
  • Hexadecimal numbers (0xFF)
  • Infinity, -Infinity, and NaN
// config.json5
{
  // This is valid JSON5
  database: {
    host: 'localhost',
    port: 5432,
    name: 'myapp',  // trailing comma is OK
  },
  timeout: 5_000,   // underscores in numbers
  debug: false,
}

JSON5 is well-suited for human-edited config files where readability matters more than strict machine interoperability. Libraries: json5 (npm, CDN), pyjson5 (Python).

When to use JSON5 vs JSONC: JSONC only adds comments (minimal change). JSON5 adds a broader set of relaxations. If all you need is comments, JSONC is safer. If you want the full set of ergonomic improvements, JSON5 is better. Neither is valid standard JSON.

Workaround 3: YAML (Full Comment Support)

YAML is a superset of JSON (all valid JSON is valid YAML) and has native comment support using #:

# Database configuration
database:
  host: localhost
  port: 5432  # default PostgreSQL port
  name: myapp

# Timeout in milliseconds
timeout: 5000

YAML is the natural choice for config files when comments are important and the file will not be consumed by systems that require JSON. It is the format of choice for Kubernetes manifests, Docker Compose, GitHub Actions, Ansible playbooks, and many other DevOps tools.

Convert your existing JSON config to YAML using our JSON/YAML Converter - it preserves structure and lets you add # comments manually afterward.

Format & Validate Your JSON

Paste your JSON (or JSONC) to format it, check for errors, and get it ready for use. Free, instant, 100% in-browser - no data sent to any server.

Open JSON Formatter →

Workaround 4: The "_comment" Key Convention

For cases where you must use standard JSON but still want human-readable annotations, use a reserved key as a comment placeholder. The community has settled on a few conventions:

{
  "_comment": "Database configuration - do not change timeout below 3000ms",
  "timeout": 5000,
  "retries": 3,

  "endpoints": {
    "//": "Primary API - failover to backup if 503",
    "primary": "https://api.example.com",
    "backup": "https://backup.api.example.com"
  }
}

Common comment key conventions:

  • "_comment" - most readable, underscore signals it is meta-data
  • "//" - visually resembles a code comment
  • "#" - resembles a shell/YAML comment
  • "__comment__" - double underscore dunder convention

Drawbacks: These are real data fields. They add bytes to the payload. If multiple comments exist at the same level, only the last one survives (duplicate key issue). Your code must explicitly ignore them. Still, for simple annotation of config files that must remain .json, this works.

Workaround 5: Strip Comments Before Parsing

Crockford's original suggestion: write your JSON with comments (accepting that it is not valid JSON), then strip the comments before passing to JSON.parse(). This is exactly what JSONC parsers do internally.

// Node.js: strip comments manually
function stripComments(jsonStr) {
  return jsonStr
    // Remove block comments (/* ... */)
    .replace(/\/\*[\s\S]*?\*\//g, '')
    // Remove line comments (// ...)
    .replace(/\/\/[^\n]*/g, '')
    // Remove trailing commas before } or ]
    .replace(/,(\s*[}\]])/g, '$1');
}

const raw = fs.readFileSync('config.json', 'utf8');
const config = JSON.parse(stripComments(raw));

Warning: This naive regex approach can fail on edge cases: // inside a string value, or /* in a URL. Use a proper JSONC parser for production code.

Step-by-Step: Choosing the Right Workaround

  1. Is this a VS Code or TypeScript config file? Use JSONC. These tools already support it natively, and the file extension (.json or .jsonc) does not matter for those consumers.
  2. Is this a human-edited config that will never be parsed by a strict JSON parser? Use JSONC or JSON5. Rename to .jsonc or .json5 to make it clear to editors and parsers.
  3. Is this a DevOps config file (CI, Docker, Kubernetes)? Consider YAML. It has native comment support and is the standard for most DevOps tooling.
  4. Must it remain valid standard JSON? Use the "_comment" key convention for important annotations, keep comments minimal, and rely on external documentation for complex explanations.
  5. Is this an API request/response payload? Do not add comments. API JSON is machine-to-machine. Use JSON Schema documentation instead to explain field meanings.

Practical Example: Annotating a CI Config

Suppose you have a CI configuration that currently uses JSON and you want to add comments. Here is how to migrate to JSONC:

// Before: .ci/config.json (no comments)
{
  "timeout": 600,
  "parallelism": 4,
  "cache": true
}

// After: .ci/config.jsonc (JSONC with comments)
{
  // Build timeout in seconds - increase if deploy job times out
  "timeout": 600,

  // Number of parallel test runners - keep at 4 to avoid OOM on t3.medium
  "parallelism": 4,

  // Cache node_modules between runs - set false to debug dependency issues
  "cache": true
}

Frequently Asked Questions

Can I add comments to package.json?

No - package.json is parsed by npm and yarn as strict JSON. Adding comments will break npm install. If you need to document your package.json, use the "description" field for the package, and for individual scripts consider using longer descriptive names or keeping a separate SCRIPTS.md. Some developers use a "//scripts-docs" key as a documentation object, which npm ignores.

Does tsconfig.json support comments?

Yes. Despite having a .json extension, TypeScript's compiler uses a JSONC parser for tsconfig.json. You can freely add // and /* */ comments. The TypeScript language server in VS Code also understands them. However, if you pass tsconfig.json to a non-TypeScript tool that expects JSON, it will fail.

What is the difference between JSONC and JSON5?

JSONC adds only comments to JSON. JSON5 adds comments plus many other relaxations: trailing commas, unquoted keys, single-quoted strings, multi-line strings, and special number values. JSONC is the minimal change; JSON5 is the maximum ergonomics. Both require their own parsers and are not valid standard JSON.

Why do some validators accept my JSON with comments?

Some tools (like VS Code's built-in JSON editor, or certain online JSON validators) use a JSONC parser internally and show comments as valid. This can be confusing because pasting that same content into JSON.parse() or a strict API will throw an error. Always test with JSON.parse() if the JSON will be consumed by a standard parser.

Is there a way to add comments that works everywhere?

No perfect solution exists. The closest is the "_comment" key convention - it is valid standard JSON, preserved through all parsers, and works in any environment. The trade-off is that it adds data to your payload and you need code to ignore those keys. For production API payloads, avoid all comment workarounds entirely and document with JSON Schema.

Format your JSON and catch any comment-related syntax errors → Use our free JSON Formatter.

UK
Written by Usman Khan
DevOps Engineer | MSc Cybersecurity | CEH | AWS Solutions Architect

Usman has 10+ years of experience securing enterprise infrastructure, managing high-traffic servers, and building zero-knowledge security tools. Read more about the author.