Development

JSON vs JSONC vs JSON5: The Complete Guide for Devs

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.


The Quick Answer (3-Way Comparison You Can Screenshot)

If you’re in a hurry, here’s the cheat sheet. Bookmark it, screenshot it, tape it to your monitor — whatever works.

20-Second Definitions

  • JSON — The strict interchange syntax standardized in RFC 8259. No comments. No trailing commas. Double-quoted strings and keys only. Every parser on the planet speaks it.
  • JSONC — “JSON with Comments.” Adds // 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.
  • JSON5 — A formally specified superset of JSON (spec.json5.org) inspired by ECMAScript 5.1. Comments, trailing commas, unquoted keys, single-quoted strings, hex numbers, Infinity, NaN, and multiline strings.

JSON vs JSONC vs JSON5 Feature Matrix

Here’s the side-by-side that answers 90% of the questions people Google about these formats:

FeatureJSONJSONCJSON5
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 specificationRFC 8259 / ECMA-404Draft (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.


What “Strict JSON” Really Means (And Why It Breaks on Comments)

The JSON Grammar Constraints (Practical Implications)

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
}
JSON

Fig: JSON Token Model

Numbers: Why JSON Forbids Infinity and NaN

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.

Interop Note: Why “Extensions” Cause Pipeline Failures

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 Explained (And Why the Term Is Confusing)

Usage of JSONC in the Real World (VS Code + Tooling)

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"
  }
}
JSONC

This is great for tools like Turbo, Biome, or ESLint that support comments in their JSON config files but use a .json extension.

JSONC Specification Landscape

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.

Trailing Commas Are the Trap

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.

Disambiguation: JSONC vs JSON-C (And Other Meanings)

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.

Is JSONC the same as JSON-C?

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 Explained (Superset, Not Just Comments)

Official Definition + Positioning (“For Humans”)

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.

Summary of Features (Tied to Real-Life Pain Points)

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 numbers0xDECAF 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

File Extension + Ecosystem Adoption

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'));
JavaScript

Python has a json5 package on PyPI that works the same way. The ecosystem is mature and actively maintained.

JSON5 Is a Superset of JSON (What That Guarantees — And What It Doesn’t)

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.


Side-by-Side Examples (The “One Config, Three Formats” Section)

Example Dataset: A Realistic App Config

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.

Strict JSON Version

{
  "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
  }
}
JSON

Clean 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.

JSONC Version (Comments + Optional Trailing Commas)

{
  // 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
  }
}
JSONC

Now 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.

JSON5 Version (Comments + Broader Relaxed Syntax)

{
  // 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,
  },
}
JSON5

Notice 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.

Round-Trip Conversion Outputs (Normalize Everything to JSON)

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
  }
}
JSON

Comments 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.


Compatibility and Tooling (Where Teams Actually Get Burned)

Parser Compatibility Matrix

The format you author in determines which parsers can read it. This table covers the most common scenarios:

File FormatJSON.parse() (JS)jsonc-parser (npm)json5 (npm)Python jsonPython json5jq
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.

Editor + IDE Behavior (Validation, Schema, Warnings)

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.

Schema Validation Reality Check

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)

Comment-Preserving Edits vs “Parse + Stringify Loses Comments”

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.


When to Use JSON vs JSONC vs JSON5 (Decision Framework)

Decision Tree for JSON vs JSONC vs JSON5

Use JSON When…

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 When…

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 When…

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.


Conversion and CI (Make It Safe and Boring)

Convert JSON5 → JSON in Build/CI

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.json5
Bash

In 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.json
Bash

JSONC → JSON Preprocessing

For 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));
JavaScript

Watch 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.

FAQs

Is JSON5 valid JSON?

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.

Does JSON allow comments?

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.

What’s the difference between JSONC and JSON5?

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.

Is JSONC a standard?

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.

Why do some JSONC parsers reject trailing commas while VS Code accepts them?

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.

Is JSONC the same as JSON-C?

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.

Rana Ahsan

Rana Ahsan is a seasoned software engineer and technology leader specialized in distributed systems and software architecture. With a Master’s in Software Engineering from Concordia University, his experience spans leading scalable architecture at Coursera and TopHat, contributing to open-source projects. This blog, CodeSamplez.com, showcases his passion for sharing practical insights on programming and distributed systems concepts and help educate others. Github | X | LinkedIn

Recent Posts

SnapDrift: Free Auto Visual Regression Testing On GitHub Actions

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…

4 weeks ago

Local LLM for Coding: Free AI Coding Agent With Ollama + Claude

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…

1 month ago

Best AI Coding Agents in 2026: The Complete Beginner’s Guide

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…

2 months ago

This website uses cookies.