You’ve opened a config file, dropped in a helpful // comment, and watched your parser explode. I’ve been there — probably dozens of times before I finally sat down and learned what’s actually going on with JSON vs JSONC vs JSON5. These three formats look nearly identical, yet they break in completely different ways depending on the tool you’re using. This guide gives you everything you need to pick the right format, avoid the common traps, and wire it all into a CI pipeline that doesn’t catch fire at 2 AM.
JSON is a strict, lightweight data-interchange format defined by RFC 8259: no comments allowed, no trailing commas, double-quoted keys and strings only.
JSONC adds comments on top of JSON (popularized by VS Code), while JSON5 is a formal superset that also relaxes rules around keys, strings, and numbers. All three encode the same underlying data — they disagree on how much human-friendliness the syntax should allow.
If you’re in a hurry, here’s the cheat sheet. Bookmark it, screenshot it, tape it to your monitor — whatever works.
// and /* */ comments. Behavior around trailing commas varies by parser. Popularized by Microsoft for VS Code config files; a draft spec exists at jsonc.org, but tooling support isn’t universal.Infinity, NaN, and multiline strings.Here’s the side-by-side that answers 90% of the questions people Google about these formats:
| Feature | JSON | JSONC | JSON5 |
|---|---|---|---|
Single-line comments (//) | ❌ | ✅ | ✅ |
Block comments (/* */) | ❌ | ✅ | ✅ |
| Trailing commas | ❌ | ⚠️ Varies by parser | ✅ |
| Single-quoted strings | ❌ | ❌ | ✅ |
| Unquoted keys | ❌ | ❌ | ✅ |
| Multiline strings | ❌ | ❌ | ✅ |
Hex numbers (0xFF) | ❌ | ❌ | ✅ |
Infinity / NaN | ❌ | ❌ | ✅ |
Leading/trailing decimal (.5, 5.) | ❌ | ❌ | ✅ |
| File extension | .json | .jsonc (or .json in VS Code) | .json5 |
| Formal specification | RFC 8259 / ECMA-404 | Draft (jsonc.org) | spec.json5.org |
🚨 Callout: If you’re building APIs, use JSON. Period. JSONC and JSON5 exist for human-authored files like configs and manifests. The moment data leaves your service boundary, it should be strict JSON.
JSON’s grammar is intentionally tiny. According to RFC 8259, a JSON text is a serialized value, and values can only be objects, arrays, numbers, strings, true, false, or null. Between these tokens, only four whitespace characters are legal: space (U+0020), horizontal tab (U+0009), line feed (U+000A), and carriage return (U+000D).
That’s it. There is no production rule for comments. There is no “ignored content” category. The grammar defines exactly what can appear between tokens, and // or /* aren’t on the list.
This is why you can’t just “add comments to JSON.” It’s not a missing feature — it’s a deliberate grammar constraint. Douglas Crockford, who created JSON, removed comments intentionally because people were using them to embed parsing directives, which destroyed interoperability.
The same strict grammar is why trailing commas fail. An object production in JSON is { } or { member *( , member ) }. There’s no rule that allows a comma after the last member. A trailing comma is a syntax error, not a style choice.
// This is NOT valid JSON — two different errors:
{
"name": "myapp", // ← comment: syntax error
"version": "1.0", // ← trailing comma: syntax error
}JSONFig: JSON Token Model
JSON numbers are defined by a specific grammar: an optional minus sign, digits, an optional decimal fraction, and an optional exponent. There’s no production for Infinity, -Infinity, or NaN. Why? Because these IEEE 754 special values don’t have universal representations across programming languages. A Python script writing NaN into a JSON file could crash a Java parser that doesn’t expect it. Strict JSON keeps numbers portable by limiting them to finite decimal representations.
Here’s where teams get burned: one developer writes a config with comments, another tool in the pipeline uses JSON.parse(), and the build fails. JSON parsers are correct when they reject comments — that’s the spec working as designed. If you need comments, you need a different format or a preprocessing step. Don’t patch around it by hoping every tool in your chain has a lenient mode.
Pro Tip💡: Learn about how to use JSON in NodeJS.
JSONC — “JSON with Comments” — is most closely associated with Visual Studio Code. When VS Code opens files like settings.json, launch.json, or tsconfig.json, it automatically switches to its “JSON with Comments” language mode. In this mode, you get // and /* */ support, plus syntax highlighting and IntelliSense.
VS Code’s JSONC mode also accepts trailing commas, but it displays a warning squiggle under them. This is the source of enormous confusion. Developers see trailing commas working in VS Code and assume they’re part of the JSONC “standard.” They’re not — VS Code tolerates them as a convenience for editing, but the behavior is specific to VS Code’s internal parser.
You can associate any file with JSONC mode in VS Code by adding a files.associations entry:
// .vscode/settings.json
{
"files.associations": {
"turbo.json": "jsonc"
}
}JSONCThis is great for tools like Turbo, Biome, or ESLint that support comments in their JSON config files but use a .json extension.
For a long time, JSONC had no formal specification — it was just “whatever VS Code does.” That changed with the jsonc.org draft specification, which aims to formalize the format as what Microsoft’s jsonc-parser considers valid using its default settings.
The key detail: the jsonc.org spec excludes trailing commas from the baseline format. The spec explicitly states that trailing commas are not part of standard JSONC, even though VS Code accepts them. The rationale is compatibility — TSConfig files, ESLint configs, and most other JSONC consumers reject trailing commas. The recommended file extension is .jsonc.
This is the single biggest gotcha with JSONC. Microsoft’s jsonc-parser library has an allowTrailingComma option that defaults to false. VS Code sets it to true for its own config files. So the same parser behaves differently depending on who’s calling it.
What does this mean in practice? If you write a JSONC file with trailing commas and it works in VS Code, there’s no guarantee it’ll work in your CI linter, your teammate’s editor plugin, or any other JSONC-aware tool. Treat trailing commas as a VS Code convenience, not a JSONC feature.
Pro Tip: If you want trailing commas and comments and broad tooling support, skip JSONC and use JSON5. It’s a proper superset with a real spec that guarantees trailing comma support.
Don’t confuse JSONC (JSON with Comments) with JSON-C, which is a completely unrelated C library for working with JSON objects. JSON-C is a mature open-source project for parsing and serializing JSON in C programs. The naming collision is unfortunate but unavoidable.
There’s also a separate JSONC spec on GitHub by stephenberry that positions itself as a simpler alternative focused purely on comments. Bottom line: when someone says “JSONC,” ask which one they mean.
No. JSONC (“JSON with Comments”) is a JSON syntax extension that adds comment support, popularized by VS Code. JSON-C is a C programming library for parsing and generating standard JSON. They share a name but have zero overlap in purpose.
JSON5 is a formally specified data interchange format that extends JSON with syntax features borrowed from ECMAScript 5.1. It was started in 2012, and the npm package now gets over 65 million downloads per week. Major projects including Chromium, Next.js, Babel, and WebStorm use it natively.
The positioning is explicit: JSON5 is for human-authored files. The official site states it’s not intended for machine-to-machine communication — keep using strict JSON for that.
Every JSON5 feature solves a specific annoyance you’ve hit while editing JSON by hand:
Unquoted keys — If the key is a valid ECMAScript identifier, you can drop the quotes. { port: 3000 } is valid JSON5. This eliminates the most tedious part of hand-writing config files.
Single-quoted strings — 'hello' is just as valid as "hello". This is a lifesaver when your string value contains a lot of double quotes and you’re tired of escaping them.
Multiline strings — Prefix each newline with a backslash, and your string can span multiple lines. No more concatenating segments or using \n everywhere.
Hex numbers — 0xDECAF is a valid number. Useful for color values, bitmasks, or memory addresses in config files.
Infinity, -Infinity, NaN — IEEE 754 special values are first-class citizens. Scientific and engineering configs can represent these directly.
Leading/trailing decimal points — .5 and 5. are both valid. Minor, but it matches how most developers actually type numbers.
Trailing commas — In both objects and arrays. This is guaranteed behavior, not a “maybe” like JSONC.
Comments — Both // single-line and /* */ block comments, identical to JavaScript.
{
// Server configuration
host: 'localhost',
port: 3000,
maxRetries: 5,
/* Feature flags for v2 launch */
features: {
darkMode: true,
betaAPI: false,
},
// Hex color for the admin dashboard
accentColor: 0x3B82F6,
// Timeout in ms — use Infinity to disable
sessionTimeout: Infinity,
}JSON5💡Validate/Beautify JSON data With JSON Formatter
JSON5 files use the .json5 extension. This is critical for tooling — it tells parsers, editors, and linters exactly what syntax to expect. IntelliJ IDEA supports JSON5 out of the box. VS Code can handle it with a plugin or by associating the extension.
In Node.js, you can parse JSON5 files using the json5 npm package, which mirrors the native JSON API:
import JSON5 from 'json5';
import { readFileSync } from 'fs';
const config = JSON5.parse(readFileSync('./config.json5', 'utf8'));JavaScriptPython has a json5 package on PyPI that works the same way. The ecosystem is mature and actively maintained.
Every valid JSON file is automatically a valid JSON5 file. You can rename .json to .json5 and it will parse without changes. The reverse is not true — a JSON5 file using unquoted keys or single quotes will fail in a strict JSON parser. This one-way compatibility is the whole point: you can adopt JSON5 gradually without breaking existing files.
Let’s take a real-world scenario: a web application’s server configuration. It has a host, port, database connection, feature flags, and a couple of tricky values (a timeout that can be infinite, a hex color code). This is exactly the kind of file developers edit by hand.
{
"server": {
"host": "localhost",
"port": 3000,
"timeout": 30000
},
"database": {
"connectionString": "postgres://localhost:5432/myapp",
"poolSize": 10
},
"features": {
"darkMode": true,
"betaAPI": false
},
"ui": {
"accentColor": "#3B82F6",
"maxUploadSizeMB": 25
}
}JSONClean and universal. Every parser on Earth handles this. But there’s no way to explain why the pool size is 10, or why the timeout is 30000ms, or what betaAPI actually controls. The config is clear about what, silent about why.
{
// Server settings — these match our Docker Compose defaults
"server": {
"host": "localhost",
"port": 3000,
"timeout": 30000 // ms — increase to 60000 for slow DB queries
},
"database": {
"connectionString": "postgres://localhost:5432/myapp",
/* Pool size: keep at 10 for dev.
Production uses 50 (set via env var override). */
"poolSize": 10
},
"features": {
"darkMode": true,
"betaAPI": false // Flip to true after QA signs off on v2 endpoints
},
"ui": {
"accentColor": "#3B82F6",
"maxUploadSizeMB": 25
}
}JSONCNow the config is self-documenting. A new developer joining the team can understand the intent behind every value without digging through Confluence pages.
⚠️ Callout: I intentionally avoided trailing commas here. They work in VS Code’s JSONC mode, but many JSONC parsers reject them by default. Stick to comments-only if you want maximum JSONC compatibility.
{
// Server settings — match Docker Compose defaults
server: {
host: 'localhost',
port: 3000,
timeout: 30000, // ms — increase for slow DB queries
},
database: {
connectionString: 'postgres://localhost:5432/myapp',
/* Pool size: keep at 10 for dev.
Production uses 50 (set via env var override). */
poolSize: 10,
},
features: {
darkMode: true,
betaAPI: false, // Flip after QA signs off on v2
},
ui: {
accentColor: 0x3B82F6, // Hex color — no string quoting needed
maxUploadSizeMB: 25,
},
}JSON5Notice the differences: unquoted keys, single-quoted strings, trailing commas on every item, and the hex color value is an actual number instead of a string. The file reads almost like JavaScript object notation — because that’s exactly what JSON5 is modeled on.
Regardless of which format you author in, the downstream output should be strict JSON. Here’s what both the JSONC and JSON5 examples above produce after parsing and re-serializing:
{
"server": {
"host": "localhost",
"port": 3000,
"timeout": 30000
},
"database": {
"connectionString": "postgres://localhost:5432/myapp",
"poolSize": 10
},
"features": {
"darkMode": true,
"betaAPI": false
},
"ui": {
"accentColor": 3915510,
"maxUploadSizeMB": 25
}
}JSONComments are gone. Keys are double-quoted. The hex color became a decimal integer. This is the artifact your application code actually consumes.
💡: Have you ever debugged a deployment failure that turned out to be a trailing comma? You’re not alone — it’s one of the most common config-file issues in CI pipelines.
The format you author in determines which parsers can read it. This table covers the most common scenarios:
| File Format | JSON.parse() (JS) | jsonc-parser (npm) | json5 (npm) | Python json | Python json5 | jq |
|---|---|---|---|---|---|---|
| Strict JSON | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| JSONC (comments only) | ❌ | ✅ | ✅ | ❌ | ✅ | ❌ |
| JSONC (comments + trailing commas) | ❌ | ⚠️ Opt-in | ✅ | ❌ | ✅ | ❌ |
| JSON5 (full syntax) | ❌ | ❌ | ✅ | ❌ | ✅ | ❌ |
Key takeaway: JSON5 parsers can read everything below them (JSON5 ⊃ JSONC ⊃ JSON). Strict JSON parsers can only read strict JSON. Plan your toolchain accordingly.
VS Code handles this better than most editors. It distinguishes between “JSON” and “JSON with Comments” language modes and applies different validation rules to each. Files like tsconfig.json and settings.json are automatically assigned JSONC mode. You can extend this to any file via files.associations.
JetBrains IDEs (IntelliJ, WebStorm) support JSON5 natively. They recognize .json5 files and apply the correct syntax rules without plugins.
Vim/Neovim requires plugins for JSONC or JSON5 syntax highlighting. Without them, you’ll get false error indicators on every comment line.
The trap 🪤: if your editor shows no errors but your CI parser rejects the file, the editor’s language mode and the parser’s expected format are mismatched. Always verify that the file extension, editor mode, and parser all agree on the format.
JSON Schema files are themselves strict JSON. This creates a practical tension: your schema definitions must be valid JSON, but the config files they validate might be JSONC or JSON5.
The solution is a preprocessing step. Author your config in JSONC or JSON5, strip it to strict JSON at build time, then validate the stripped output against your schema. Don’t try to validate JSONC/JSON5 directly with a JSON Schema validator — most validators use JSON.parse() internally and will reject comments before they even reach the schema logic.
<code>config.json5 → json5 parse → strict JSON → schema validate → ✅</code>Code language: HTML, XML (xml) If you round-trip a JSONC or JSON5 file through a standard parse-and-stringify cycle, every comment disappears. Some specialized tools (like VS Code’s internal editor engine) preserve comments during edits by working with concrete syntax trees instead of abstract value representations. If you need programmatic edits that preserve comments, look for libraries that operate on the CST level rather than parse-to-value.
Decision Tree for JSON vs JSONC vs JSON5
Use strict JSON for APIs, public data contracts, and anything that crosses a service boundary. JSON is the lingua franca of data interchange — every programming language has a built-in or standard-library parser. Use it for REST API responses, webhook payloads, database-stored documents, and anything consumed by third-party systems. The universal compatibility is worth the verbosity.
Also use JSON when you’re generating files programmatically. Machines don’t need comments or trailing commas. A JSON.stringify() call produces perfectly valid, perfectly interoperable output.
Use JSONC for config files in ecosystems that already support it — primarily VS Code, TypeScript (tsconfig.json), and tools that explicitly accept comments in .json files. JSONC is the pragmatic choice when you need comments but don’t want to introduce a new file extension or dependency.
The prerequisite: you control the parser. If you know every tool in your pipeline handles JSONC, go for it. If there’s any ambiguity — if a CI step might use JSON.parse() — either switch to JSON5 (which has a formal spec) or add a preprocessing step.
Use JSON5 for human-authored configuration files where you want the full suite of relaxed syntax: comments, trailing commas, unquoted keys, single quotes, and extended number formats. JSON5 is the right choice when configs are complex enough that readability matters and you’re willing to add the json5 parser to your toolchain.
JSON5 shines for developer-facing configs in projects like Babel, Chromium, and Next.js. If your config file benefits from looking more like JavaScript than like a data dump, JSON5 is your format.
🚨 Callout: If you must publish to third parties, ship strict JSON. JSONC and JSON5 are for files you control. Public contracts demand universal compatibility.
The json5 CLI can convert and validate JSON5 files in one step:
# Install the CLI globally
npm install -g json5
# Convert a JSON5 file to strict JSON
json5 -c config.json5
# Outputs config.json in the same directory
# Validate without converting (exit code 0 = valid)
json5 -v config.json5BashIn a CI pipeline, wire this into your build step so the application never sees JSON5 at runtime:
# In your CI script
json5 -c src/config.json5 -o dist/config.jsonBashFor JSONC files, you can use Microsoft’s jsonc-parser or a simple regex strip (for comments only — not recommended for production). A more robust approach:
import { parse } from 'jsonc-parser';
import { writeFileSync } from 'fs';
import { readFileSync } from 'fs';
const raw = readFileSync('config.jsonc', 'utf8');
const data = parse(raw); // strips comments, rejects trailing commas by default
writeFileSync('config.json', JSON.stringify(data, null, 2));JavaScriptWatch out: if your JSONC file has trailing commas and the parser’s allowTrailingComma is false (the default), this will throw. Either remove trailing commas from your source file or explicitly enable the option.
The cleanest pattern is: source-of-truth config (JSONC or JSON5) → compile to strict JSON artifact → deploy the artifact. This gives you human-friendly authoring with machine-friendly output. Version-control the source file. Generate the JSON artifact in CI. Never hand-edit the generated file.
No — but the reverse is true. Every valid JSON file is automatically valid JSON5, because JSON5 is a superset of JSON. However, a JSON5 file that uses features like unquoted keys or single-quoted strings is not valid JSON and will fail in a strict JSON parser.
No. The JSON grammar (RFC 8259) defines only six structural characters, four whitespace characters, and value types. Comments aren’t part of the grammar. This is by design — Douglas Crockford removed them to prevent interoperability problems.
JSONC is “JSON plus comments” — it adds // and /* */ support but doesn’t change the core JSON syntax for keys, strings, or numbers. JSON5 is a broader superset that adds comments and relaxed syntax for unquoted keys, single-quoted strings, trailing commas, hex numbers, Infinity, NaN, and multiline strings.
Not an IETF or ECMA standard. A draft specification exists at jsonc.org, which aims to formalize the format based on Microsoft’s jsonc-parser defaults. In practice, JSONC behavior varies by toolchain — what VS Code accepts and what a standalone JSONC parser accepts can differ, especially around trailing commas.
VS Code’s internal JSONC mode sets allowTrailingComma: true for its own config files as a convenience. But Microsoft’s jsonc-parser library defaults to allowTrailingComma: false. Other tools like TSConfig and ESLint also reject trailing commas in JSONC files. The jsonc.org spec explicitly excludes trailing commas from the baseline format. So VS Code is the exception, not the rule.
No. JSONC (“JSON with Comments”) is a syntax extension that adds comment support to JSON, popularized by VS Code. JSON-C is an unrelated C programming library for parsing and serializing standard JSON data. Same abbreviation, completely different projects.
SnapDrift is a free, open-source visual regression testing tool built for GitHub Actions. It captures full-page screenshots on every push, compares them pixel-by-pixel against your…
This guide walks you through setting up a fully private, local LLM for coding on your own hardware. From model selection and hardware planning to…
The best AI coding agents in 2026 don't just autocomplete your lines — they plan, execute, and debug entire features autonomously. Whether you're a weekend…
This website uses cookies.