JSON has become a near-ubiquitous data format, used in API responses, save game files, and configuration. But many people feel it can be better, and various attempts have been made to expand or improve it. JSONC is one of those attempts.
What is JSONC, and why was it created?
JavaScript Object Notation (JSON) is a human-readable text format for the storage of structured data, using name-value pairs, arrays, and scalar values. It was heavily influenced by JavaScript syntax—hence the name—but is now used by almost every programming language, across many different types of environments, as a neutral format for data interchange.
Despite it…
JSON has become a near-ubiquitous data format, used in API responses, save game files, and configuration. But many people feel it can be better, and various attempts have been made to expand or improve it. JSONC is one of those attempts.
What is JSONC, and why was it created?
JavaScript Object Notation (JSON) is a human-readable text format for the storage of structured data, using name-value pairs, arrays, and scalar values. It was heavily influenced by JavaScript syntax—hence the name—but is now used by almost every programming language, across many different types of environments, as a neutral format for data interchange.
Despite its popularity, JSON has its critics. The most common complaints are about its syntax, and they’re usually one of the following:
- It doesn’t allow comments.
- It doesn’t allow trailing commas (a comma after the last item in an array or the last property in an object).
- It requires keys (property names) to be double-quoted.
- It has no support for multiline strings.
In other words, this is invalid JSON:
{ // One of "dark", "light", or "auto" theme: "light", description: "This is a description wrapped over multiple lines for ease of reading", // I like LOADS of spaces! tab-width: 8,}
Instead, that data needs to be written like this:
{ "theme": "light", "description": "This is a description wrapped over multiple lines for ease of reading", "tab-width": 8}
JSONC is one attempt, of many, to improve JSON. Other formats that try to do something similar include YAML and JSON5. Each of these is a superset of JSON, so valid JSON is also valid JSONC, YAML, and JSON5. The formats differ in just how much they try to expand JSON’s syntax.
YAML makes significant changes and has found a niche in configuration and, occasionally, documentation. The format is a bit of a hybrid between Markdown and JSON, with indentation for nesting, custom data types, and multiline strings. YAML is used by projects including Docker Compose, workflows in GitHub Actions, and the Ruby on Rails framework.
JSON5, meanwhile, is valid JavaScript, like JSON, so it sticks more rigidly to that syntax. JSON5 aims to fix all the above complaints about JSON, and more, but it remains very similar to JSON. JSON5 is used in Chromium, Next.js, and macOS programming.
JSONC, on the other hand, is “JSON with Comments”, so it focuses entirely on allowing comments within JSON data. This means that it supports a hybrid of the two previous examples:
{
// One of "dark", "light", or "auto"
"theme": "light",
/*
I like LOADS
of spaces!
*/
"tab-width": 8
}
JSONC supports two common forms of comments:
- Inline comments begin with // and last only until the end of their line.
- Block comments start with /* and end with */ and can contain any number of lines.
The third common form of comment—the same as inline, but starting with a single “#” character—is not supported.
What are the benefits and drawbacks of JSONC?
JSONC is much less popular than JSON, which is in itself a drawback. So what does JSONC bring to the table, and is it enough for the alternative format to become successful?
First, I personally think that comments are a bigger win than fixing any of the other common JSON complaints. Changes to syntax to handle quotes and commas may make things more convenient, but they don’t provide any benefits that are quite as fundamental. Comments in JSON files have two significant uses:
- Configuration files: Comments can act as examples or help text in config templates, and they can also be used to explain why a particular configuration has been chosen.
- Data Annotation: Developers can include comments alongside data to explain its purpose or how it interoperates with other data.
Comments can also be used to temporarily disable sections of code, e.g. in source code files, for debugging or testing. But this usage is less common in data files, like JSON, since they could easily cause confusion when passing data between different sources.
Comments provide a means of self-contained documentation; without them, JSON files must be explained elsewhere, in a place that might not be obvious or easily available. Another possible workaround is to add “dummy” data, e.g.:
{
"theme-comment": "The theme value should be one of 'dark', 'light', or 'auto'",
"theme": "dark"
}
Although this can work, it’s brittle because it relies on any system reading this data to ignore keys it doesn’t recognize.
Bear in mind, though, that comments aren’t universally beneficial. Douglas Crockford, the original specifier of JSON, is probably the best person to make this argument:
I removed comments from JSON because I saw people were using them to hold parsing directives, a practice which would have destroyed interoperability.
In other words, comments are ripe for abuse, which forbidding them prevents.
It doesn’t handle trailing commas or unquoted keys
As I explained above, I consider this less important, but it’s still a minor downside. If we’re going to try to fix JSON with a backward-incompatible upgrade, we might as well fix everything we can.
Trailing commas are easier to maintain, resulting in fewer bugs and cleaner patches. JSON doesn’t allow them for historical reasons relating to the messy syntax of JavaScript. But we can fix that now, and we probably should, even if the benefits are minimal.
JSONC is not compatible with JSON
Although JSONC is a superset of JSON, so all valid JSON is also valid JSONC, that doesn’t work the other way round. Most tools that require JSON will fail if you try to use them with a JSONC file:
This might not be a problem for your own usage, but it makes widespread adoption of JSONC that much more difficult.
It’s awkward to preprocess
Interoperability is less of a problem if JSONC can be easily converted into JSON. You can use Douglas Crockford’s JSMin tool to do just this. But JSONC’s chosen comment syntax means that it has to be a full-blown JSON parser to make sure comments are recognized in context correctly.
If, instead, comments were indicated with a single “#” character in column 0, a converter would be trivial:
<input.jsonc grep -v '^#' >output.json
This would mean any JSON parser could easily be updated to support JSONC, rather than having to make more significant code changes or rely on a third-party program like JSMin.
How can I use JSONC today?
More often than not, you’ll encounter JSONC when you need to change some configuration. For example, the fastfetch program reads a configuration file in JSONC format, so you can annotate it with notes, suggestions, or anything else you care to add.
If you’re working with your own code and want to write something that handles JSONC as well as JSON, you have two main options. First, you can use a tool like JSMin and deal with JSONC in exactly the same way you already deal with JSON.
Alternatively, you can use a library that handles JSONC, removing the dependency on a separate program. The fastfetch code uses yyjson, a C library that handles JSONC comments as well as trailing commas and more besides. Microsoft’s node-jsonc-parser does a similar thing for JavaScript and also supports trailing commas.