JSON Comments Are Not Allowed: Why and What to Use Instead
Quick answer
💡JSON does not support comments. RFC 8259 defines the format with no comment syntax, and JSON.parse throws a SyntaxError on any // or /* */ comment. For config files, use the strip-json-comments npm package to strip comments before parsing, adopt the JSONC format used by VS Code, switch to JSON5, or use TOML or YAML which support comments natively.
Error symptoms
- ✕
SyntaxError: Unexpected token / in JSON at position 12 when calling JSON.parse - ✕
JSON.parse throws with Unexpected token # when a config file uses hash comments - ✕
A configuration file edited by hand is rejected by the loader after adding an explanation comment - ✕
tsconfig.json or settings.json accepts comments but a custom config loader does not - ✕
Coworkers ask why documentation is inside a string field named _comment instead of a real comment - ✕
A third-party JSON file with comments cannot be imported using a standard JSON import
Common causes
- •Copying documentation examples that use JavaScript-style comments into a JSON file
- •Editing tsconfig.json or .vscode/settings.json and assuming all JSON parsers accept comments the same way
- •Using a text editor that does not warn about invalid JSON when saving a file with comments
- •Pasting a JSON5 file into a context that uses standard JSON.parse for parsing
- •Not knowing that the strip-json-comments package exists and that it solves the problem cleanly
- •Assuming JSON comments were removed accidentally and that some spec version must allow them
When it happens
- •Loading a configuration file in a Node.js application using fs.readFileSync followed by JSON.parse
- •Importing a JSON file with comments using require() or a static JSON import in a bundler
- •Writing a JSON API response in documentation with comments as annotations, which clients then try to parse
- •Editing package.json manually and accidentally leaving a comment that breaks npm install
Examples and fixes
A Node.js application loads a configuration file that developers have annotated with comments. The wrong version tries to parse it directly. The fixed version uses strip-json-comments to remove comments first.
Stripping comments from a config file before parsing with strip-json-comments
❌ Wrong
const fs = require('fs');
// This will throw SyntaxError because the config has comments
function loadConfig(filePath) {
const rawContent = fs.readFileSync(filePath, 'utf8');
return JSON.parse(rawContent);
}
// config.json contains:
// {
// "port": 3000, // The server port
// "debug": true /* Enable verbose logging */
// }
const appConfig = loadConfig('./config.json');✅ Fixed
const fs = require('fs');
const stripJsonComments = require('strip-json-comments');
function loadConfig(filePath) {
const rawContent = fs.readFileSync(filePath, 'utf8');
const stripped = stripJsonComments(rawContent);
return JSON.parse(stripped);
}
// config.json can now safely contain:
// {
// "port": 3000, // The server port
// "debug": true /* Enable verbose logging */
// }
const appConfig = loadConfig('./config.json');
console.log('Loaded config:', appConfig);strip-json-comments processes the raw string and removes both single-line and multi-line comments before the result is passed to JSON.parse. The stripped string is standard JSON with blank space where comments were, which preserves line and column numbers for error messages. This is the minimal change needed to support commented config files without switching to a different format.
A build tool configuration file needs comments explaining each option and allows trailing commas for easier editing. The wrong version uses standard JSON and cannot have comments. The fixed version uses the json5 package.
Using JSON5 for a configuration file that needs comments and trailing commas
❌ Wrong
// build.config.json — this will fail to parse
{
"entryPoints": ["src/index.ts"],
"outDir": "dist",
// Minify only in production
"minify": false,
"sourceMaps": true,
"target": "es2020",
}✅ Fixed
// build.config.json5 — valid JSON5
{
entryPoints: ['src/index.ts'],
outDir: 'dist',
// Minify only in production builds
minify: false,
sourceMaps: true,
target: 'es2020',
}
// loader.js
const JSON5 = require('json5');
const fs = require('fs');
const rawConfig = fs.readFileSync('./build.config.json5', 'utf8');
const buildConfig = JSON5.parse(rawConfig);
console.log('Build target:', buildConfig.target);JSON5 is a separate specification that extends JSON with comments, trailing commas, unquoted keys, single-quoted strings, and hexadecimal numbers. It is not compatible with JSON.parse and requires the json5 npm package. The format is well-suited for developer-facing configuration files where human readability and editability matter more than strict interoperability with all JSON parsers.
Why Crockford removed comments from JSON
Douglas Crockford, who created and standardized JSON, deliberately removed comment support in 2012. In a post on Google+, he explained his reasoning: he had observed that people were using comments to embed parsing directives in configuration files, similar to how XML processing instructions work. These directives told specific parsers to change their behavior based on comment content. Crockford realized that allowing comments would destroy interoperability, because different parsers would start reading comments differently and JSON would fragment into incompatible dialects.
The resulting specification, now codified in RFC 8259 published in 2017, defines JSON with no comment syntax at all. Section 2 of the RFC defines a JSON text as a serialized value and provides a formal grammar in which no comment production exists. The grammar covers only values, objects, arrays, strings, numbers, and the three literal names true, false, and null. A forward slash character has no special meaning in JSON grammar and appears only within strings. Encountering a slash outside of a string is therefore a syntax error.
This decision is frequently criticized by developers who want to annotate configuration files with explanations of what each setting does. The criticism is reasonable because JSON is widely used as a configuration format despite being designed primarily as a data interchange format. Configuration files benefit from comments because they document intent, warn about side effects, and explain non-obvious values. Data interchange payloads generally do not need comments because the sender and receiver share a protocol specification.
The tension between JSON's intended use as a data format and its actual widespread use as a configuration format has produced several workarounds, each with different tradeoffs. Understanding why comments are excluded from the specification helps you choose the right workaround for your situation rather than working around a mistake, because comments were not accidentally omitted from JSON.
Detecting comment syntax in failing JSON files
When JSON.parse throws a SyntaxError mentioning an unexpected token that is a slash, hash, or hyphen, the immediate diagnosis is that the file contains comments or comment-like syntax. A forward slash at the start of a comment shows up as 'Unexpected token /' in the error message. Hash symbols, which appear in TOML and Python configuration files, produce 'Unexpected token #'. An opening angle bracket from YAML document separators produces 'Unexpected token <'.
The error message includes a position number, which identifies the character offset in the string where the parser failed. To find the comment, count characters from the start of the file to that position, or divide the position by the approximate line length to estimate which line contains the problem. Modern editors with JSON syntax highlighting will underline the comment in a way that reveals the problem immediately, which is why editing a JSON file in a JSON-aware editor rather than a plain text editor catches these issues before running the code.
For configuration files loaded by build tools, the error may not appear directly as a SyntaxError from JSON.parse. The tool may wrap the error in its own message format. Webpack, for example, produces a detailed configuration error that may obscure the underlying parse failure. Looking for the words 'Unexpected token' anywhere in the error output usually reveals the root cause. Running node -e "JSON.parse(require('fs').readFileSync('file.json', 'utf8'))" from the command line is a quick way to directly test whether any JSON file is parseable by the native parser.
If you inherit a large codebase and need to find all JSON files that contain comments, a recursive grep for the pattern // or /* within .json files will identify candidates. The command grep -r '//' --include='*.json' will produce false positives for URLs in string values, so manual inspection of the results is necessary. A more precise approach is to run a linter such as ajv or jsonlint against each file, which reports syntax errors without false positives from URL strings.
strip-json-comments for config file compatibility
The strip-json-comments npm package, maintained by Sindre Sorhus, is the most straightforward solution when you want to keep writing JSON with comments in config files but need to load them with standard JSON.parse. The package accepts a string containing JSON with comments and returns a string with the comments replaced by spaces. Replacing comments with spaces rather than removing them entirely preserves the character positions of all remaining tokens, which means that if JSON.parse subsequently throws a syntax error, the error position in the stripped string maps correctly to the corresponding position in the original file.
The package supports both single-line comments starting with // and multi-line block comments delimited by /* and */. It also handles the case where a URL inside a string contains // — the package is smart enough not to treat a forward slash inside a quoted string as the start of a comment. This makes it safe to use with JSON files that contain URLs as string values.
Usage in a configuration loading function is simple: import the package, call stripJsonComments on the raw file content, then pass the result to JSON.parse. This two-step process can be abstracted into a loadJson function that replaces all direct JSON.parse calls on file content throughout the codebase. Using a centralized loading function also makes it easy to add other preprocessing steps later, such as environment variable substitution or schema validation.
For projects where every developer contributes to configuration files, adding a note to the project README or a comment in the loader code that explains the strip-json-comments preprocessing step prevents confusion when someone tries to parse the same file directly and encounters a syntax error. The .json file extension is slightly misleading in this case because the file is technically JSONC or JSON-with-comments rather than standard JSON. Some teams prefer to rename such files to .jsonc to make the format explicit.
JSON5 versus JSONC for developer configurations
JSON5 and JSONC are both supersets of JSON that add comment support, but they differ significantly in scope and intended use. JSON5, defined at json5.org, adds a substantial set of new features beyond comments: unquoted object keys that follow JavaScript identifier rules, single-quoted strings, trailing commas after the last item in objects and arrays, hexadecimal numbers, and support for positive and negative infinity and NaN as number values. JSON5 is essentially a subset of ECMAScript 5 that adds a serialization format closer to JavaScript object literal syntax.
JSONC, which stands for JSON with Comments, is a more conservative extension. It adds only single-line and multi-line comment support to standard JSON and makes no other changes to the grammar. The JSONC format is used by VS Code for its configuration files, including .vscode/settings.json, .vscode/launch.json, and .vscode/extensions.json. VS Code recognizes the .jsonc extension and enables JSONC language mode automatically. However, JSONC is not formally standardized as a distinct specification in the way JSON5 is, and different implementations may accept slightly different supersets.
The choice between JSON5 and JSONC depends on what your config file needs. If you only need comments and your tool chain can handle them, JSONC with strip-json-comments is simpler because you stay closer to standard JSON. If you also need trailing commas for easier editing, unquoted keys for brevity, or other JSON5 features, then adopting JSON5 with the json5 package gives you a richer format. However, JSON5 requires that all consumers of the file use a JSON5-aware parser, and standard JSON tooling such as JSON.parse, jq, and most API clients cannot parse JSON5 directly.
A practical consideration is tooling support. JSON5 files can be used as Webpack config if you configure the appropriate loader. TypeScript's tsconfig.json actually accepts comments and trailing commas without requiring the .jsonc extension or the JSON5 package, because the TypeScript compiler uses its own JSON reader that accepts these extras. This means tsconfig.json files look like JSONC but are technically parsed by TypeScript's custom parser, not a general JSONC library.
When tsconfig.json and settings.json accept comments
VS Code's settings.json and TypeScript's tsconfig.json are among the most widely edited JSON-like files in web development, and both accept comments and trailing commas. This creates a misleading expectation that other JSON files should also accept comments, because developers learn their habits from these files.
TypeScript's compiler uses a custom JSON parser that intentionally accepts comments and trailing commas beyond the standard JSON grammar. This is a deliberate design choice to make tsconfig.json files more human-friendly. The TypeScript team did not publish a separate JSONC specification; they simply extended their parser. Other tools that read tsconfig.json, such as ts-node and ts-jest, use the TypeScript API to read the file and therefore also accept comments. A tool that reads tsconfig.json with Node's require() or JSON.parse, however, will fail on comments.
VS Code takes a similar approach. It maintains a fork of the JSON grammar that supports JSONC, and it applies this grammar to all files in the .vscode directory as well as files with the .jsonc extension. VS Code's built-in JSON language server handles validation, completion, and hover documentation for both standard JSON and JSONC files. The distinction is visible in the status bar at the bottom of the editor, which shows either JSON or JSON with Comments as the file type.
The practical lesson is that if a specific tool accepts comments in a JSON file, it is because that tool uses a custom parser, not because JSON itself allows comments. When you write scripts that process tsconfig.json or VS Code configuration files, use the appropriate reading strategy for that specific tool rather than assuming that accepted comments make the file valid standard JSON. For tsconfig.json in particular, use the TypeScript API's readConfigFile function or parseJsonConfigFileContent rather than JSON.parse to correctly handle all the edge cases the TypeScript compiler supports.
Choosing TOML or YAML for comment-rich configs
If your configuration file fundamentally requires comments for documentation, inline explanations, or team communication, using a format designed for configuration files rather than forcing comments into JSON is the better long-term approach. TOML and YAML both support comments natively and have mature parsers in every major programming language.
TOML, which stands for Tom's Obvious Minimal Language, uses the hash symbol as a comment delimiter. A hash character and everything following it on the same line is a comment. TOML has a simple, ini-like syntax for flat key-value pairs and uses square brackets for table headers that represent nested objects. It is explicitly designed for configuration files and prioritizes readability and ease of manual editing. Rust's package manager Cargo uses TOML for Cargo.toml, and many modern tools in the Rust ecosystem follow this convention. Node.js projects can read TOML using the @ltd/j-toml or toml packages.
YAML supports both hash-prefixed line comments and is more expressive than TOML for deeply nested configuration structures. YAML is the format of choice for Kubernetes manifests, GitHub Actions workflows, Docker Compose files, and Ansible playbooks. The indentation-based structure makes YAML config files easy to read when well-formatted, though the significant whitespace is a source of bugs when indentation is inconsistent. For a configuration file that already needs to describe complex nested structures, YAML avoids the need for the excessive quoting that JSON requires.
The practical migration path from JSON config files to TOML or YAML depends on your toolchain. If your Node.js application already reads a JSON config file with JSON.parse, switching to TOML or YAML requires adding a parser dependency and updating the loading code. This is a small one-time cost that pays for itself in readability, especially for configuration files that multiple developers edit regularly. Using the yaml package for YAML or @ltd/j-toml for TOML, the loading function is nearly identical to the JSON version except for the parsing step. The resulting configuration files can be extensively commented without any preprocessing step.
Quick fix checklist
- ✓Remove all // and /* */ comments from .json files before passing them to JSON.parse
- ✓Use the strip-json-comments package to strip comments programmatically when comments are required for documentation
- ✓Rename files with comments to .jsonc if your toolchain supports the JSONC format
- ✓Use JSON5 with the json5 npm package when you need trailing commas and unquoted keys in addition to comments
- ✓Read tsconfig.json with the TypeScript API rather than JSON.parse to handle its comments correctly
- ✓Configure VS Code to treat your config file as JSON with Comments by using the .jsonc extension
- ✓Consider switching to TOML or YAML for config files that are primarily edited by humans rather than generated by tools
- ✓Do not use the _comment key hack for important documentation — it pollutes the data structure and is invisible to tooling
Related guides
Frequently asked questions
Why does JSON not support comments?
Douglas Crockford deliberately removed comment support from JSON around 2012. His reasoning was that people were using comments to embed parsing directives, which would break interoperability between different parsers. RFC 8259 codifies this decision by defining the full JSON grammar with no provision for comments of any kind.
What error does JSON.parse throw when it encounters a comment?
JSON.parse throws a SyntaxError with a message like 'Unexpected token / in JSON at position N' for single-line comments, or 'Unexpected token /' for block comment delimiters. The position N is the character offset where the comment starts. Hash comments produce 'Unexpected token #'.
How do I add comments to a JSON config file without breaking parsers?
Use the strip-json-comments npm package. Install it, then in your config loader call stripJsonComments(rawFileContent) before passing the result to JSON.parse. This removes both single-line and block comments before parsing. The package handles URLs in strings correctly and does not strip content inside quoted values.
What is JSONC and how is it different from JSON5?
JSONC adds only comment support to standard JSON. It is used by VS Code for its configuration files. JSON5 is a more expansive extension that adds comments, trailing commas, unquoted keys, single-quoted strings, and hexadecimal numbers. JSON5 requires the json5 npm package. JSONC has no single canonical parser, though strip-json-comments handles it.
Why does tsconfig.json allow comments but JSON.parse rejects them?
TypeScript uses its own custom JSON parser that deliberately accepts comments and trailing commas beyond the standard JSON grammar. When you read tsconfig.json with JSON.parse directly, it fails. Use the TypeScript API's readConfigFile function, or use strip-json-comments as a preprocessing step, to read tsconfig.json programmatically.
Can I use a string field named _comment as a workaround?
Yes, this is technically valid JSON. Adding a field like '_comment': 'This value controls X' creates a parseable document. However, the comment field becomes part of the data and can cause problems if the schema requires no additional properties. It also makes comments invisible to code editors that show key-value pairs rather than treating them specially.
What formats support comments natively and are good for config files?
TOML uses the hash symbol for comments and is designed specifically for configuration files. YAML uses the hash symbol as well and supports complex nested structures. Both have mature parsers in all major languages. For Node.js, the @ltd/j-toml package parses TOML and the yaml package parses YAML with full comment support.
Does VS Code's JSON validator accept comments in all JSON files?
VS Code applies JSONC parsing to files with the .jsonc extension and to files in the .vscode directory. For other .json files, it uses standard JSON validation. You can manually set the language mode to JSON with Comments for any file using the language selector in the status bar, which disables comment warnings for that session.
All tools run in your browser. Your data never leaves your device. Last updated: 2026-05-05.