JSON6 Syntax Reference
Whitespace, comments, keywords, values and a grammar summary for the json-6 parser, verified against version 1.1.7.
TL;DR: A JSON6 document is exactly one value, optionally surrounded by whitespace and comments. Comments are // and /* */ only (no #). The keywords are true, false, null, undefined, Infinity and NaN. Anything after the first complete value is silently ignored by JSON6.parse.
Document structure
A JSON6 document is a single value. The value can be an object, an array, a string, a number, one of the keywords, or the empty-looking but legal undefined. Whitespace and comments may appear before and after the value. A byte order mark at the very start is treated as whitespace, so a file saved by an editor that adds a BOM still parses.
// A document is one value. This one is an object. { name: 'example', size: 0x10 }What parse() does at the edges
The edge cases below were each run through JSON6.parse in json-6 1.1.7. They show where the parser is stricter than you might expect and where it is looser.
| Input | Result | Comment |
|---|---|---|
| throws "No value found in document" | Empty text, only whitespace, or only comments all throw. This arrived in 1.1.6. |
// only a comment | throws "No value found in document" | Same rule. |
undefined | undefined | Legal. A return value of undefined does not mean failure here. |
1 2 | 1 | The second value is silently ignored. |
[1] [2] | [1] | Only the first value is returned. |
{"a":1}x | {a: 1} | Trailing garbage after a complete value is ignored. |
[1,2]] | [1, 2] | An unbalanced closing bracket after the value is ignored. |
[1,2 | throws "No value found in document" | An unterminated array reports no value rather than a missing bracket. |
} | throws "Fault while parsing; unexpected" | A stray closer at the start throws. |
[1 2] | throws "Two values with no separator between them" | A separator is required inside containers (changed in 1.1.6). |
Because trailing content is ignored, JSON6.parse is not a safe validator for "this file contains exactly one value". If you must reject trailing text, stream the document with JSON6.begin and count the values, or compare the re-serialized result.
Whitespace and line terminators
JSON6 widens JSON's four whitespace characters to the set ECMAScript calls out explicitly, minus the general "any Unicode space separator" category. The parser source tests a fixed list of code points: tab (9), line feed (10), vertical tab (11), form feed (12), carriage return (13), space (32), no-break space (160, U+00A0), byte order mark (U+FEFF), line separator (U+2028) and paragraph separator (U+2029). Commas are handled separately as separators.
| Character | Code point | JSON | JSON5 | JSON6 |
|---|---|---|---|---|
| Space | U+0020 | Yes | Yes | Yes |
| Tab | U+0009 | Yes | Yes | Yes |
| Line feed, carriage return | U+000A, U+000D | Yes | Yes | Yes |
| Vertical tab | U+000B | No | Yes | Yes |
| Form feed | U+000C | No | Yes | Yes |
| No-break space | U+00A0 | No | Yes | Yes |
| Byte order mark | U+FEFF | No | Yes | Yes |
| Line separator, paragraph separator | U+2028, U+2029 | No | Yes | Yes |
| Em space and other Zs spaces | U+2003 and others | No | Yes | No |
| Ideographic space | U+3000 | No | Yes | No |
The last two rows are a verified difference from JSON5. A document containing an em space or an ideographic space between tokens parses under JSON5 and throws fault parsing under JSON6. This mostly shows up in text pasted from word processors or from East Asian input methods. The README says only "extra whitespace characters (NBSP, VT, FF, U+2028/2029)" and does not warn about the narrower set.
Line terminators matter in two places: they end a // comment, and they are the characters that a backslash can escape inside a string. JSON6 treats LF, CR and CRLF as single line endings and also treats U+2028 and U+2029 as line terminators for comments. Error messages report line and column positions, and since 1.1.6 those positions count lines correctly inside comments and strings and for CR, LS and PS as well as LF.
Comments
Two comment forms are supported, exactly as in JavaScript. Comments are allowed anywhere whitespace is allowed, including between a key and its colon and directly after a number.
{ // a line comment ends at the line terminator a: 1, /* a block comment */ b: 2, c /* between key and colon */ : 3, d: 4/* directly after a number, valid since 1.1.7 */, }- Line comments start with
//and end at CR, LF, U+2028 or U+2029. They may also end at the end of the document, with no newline at all. By default this is silent; pass{ warnWithCommentWithoutEOL: true }to log a console warning when it happens. Before 1.1.6 the warning was always on. - Block comments start with
/*and end at the first*/. They do not nest:/* /* */ 1parses as the value 1. An unterminated block comment throws "Open comment '/*' is missing close at end of document". A block comment closes correctly after several asterisks, such as/***/(fixed in 1.1.7). - A lone slash is an error. The README says "
/followed by anything else other than/or*is an error." We confirmed[1 / 2]throws. - Hash comments are not supported. The README contains a note reading "todo:or '#'?" but the parser rejects
#:[1,#cfollowed by a newline throws "fault parsing '#' unexpected". Do not use shell-style comments.
Comments are discarded at parse time. A parse followed by a stringify never writes them back, so a tool that rewrites a JSON6 file will erase every comment. See the tools page for editing workflows that preserve them.
Keywords
Six words are values. They are case-sensitive and must be written whole: True, NULL and infinity all throw.
| Keyword | Value | In JSON? | In JSON5? | Notes |
|---|---|---|---|---|
true | Boolean true | Yes | Yes | |
false | Boolean false | Yes | Yes | |
null | null | Yes | Yes | |
undefined | undefined | No | No | New in JSON6. Legal as a top-level value, array member or object value. |
Infinity | Positive infinity | No | Yes | May be preceded by signs: -Infinity, +Infinity. |
NaN | Not a number | No | Yes | -NaN and +NaN both give NaN. |
undefined is the one keyword that has no JSON equivalent anywhere. Where JSON would need null to say "no value", JSON6 can say "explicitly undefined". After parsing, {a: undefined} has an own property a whose value is undefined, which differs from a missing key when you use "a" in obj.
An incomplete keyword throws Incomplete keyword. Before 1.1.6 the parser returned undefined for tru, which could mask truncated files. A truncated keyword is still fine as an object key, because keys are strings: {tru: 1} is a key named tru.
The same words are legal as unquoted object keys and are read as strings, so {while: 1, true: 2, null: 3, undefined: 4, NaN: 5, Infinity: 6} gives six ordinary keys. See objects and arrays for the full key rules.
Values at a glance
Every JSON6 value is one of the forms below. The linked pages give the complete rules for each.
| Value form | Quick example | Where documented |
|---|---|---|
| Object | { a: 1, 'b c': 2, `d`: 3, } | Objects and arrays |
| Array | [1, , 3,] | Objects and arrays |
| String | "x" 'x' `x` | Strings |
| Number | 1_000 0xFF 0b101 0o17 .5 -Infinity ---1 | Numbers |
| Keyword | true false null undefined Infinity NaN | This page |
Separators are commas. Inside an object a single trailing comma is allowed and a doubled comma throws. Inside an array a doubled comma is an empty member, not an error, and a single trailing comma is allowed. There is no semicolon, no equals sign and no colon-less shorthand: {a}, {a=1} and {a;1} all throw.
Grammar summary
The json-6 project does not publish a formal grammar. The summary below was derived by reading the README and probing the parser, so treat it as descriptive, not normative. Where the parser is looser than the README, the grammar describes the parser.
Document = [BOM] Skip Value Skip ; text after the first Value is ignored Skip = { WhiteSpace | LineTerminator | Comment } WhiteSpace = U+0009 | U+000B | U+000C | U+0020 | U+00A0 | U+FEFF LineTerminator = U+000A | U+000D | U+2028 | U+2029 Comment = "//" { any } ( LineTerminator | EOF ) | "/*" { any } "*/" Value = Object | Array | String | Number | Keyword Keyword = "true" | "false" | "null" | "undefined" | "Infinity" | "NaN" ; signs allowed, see Number Object = "{" Skip [ Member { Skip "," Skip Member } [ Skip "," ] ] Skip "}" Member = Key Skip ":" Skip Value Key = String | BareKey BareKey = one or more characters, none of: whitespace, quote ' " `, : , comma, [ ] { } and not starting a comment ("/" followed by "/" or "*") String = '"' chars '"' | "'" chars "'" | "`" chars "`" chars = any character, including line terminators, or an Escape (see the strings page) Array = "[" Skip [ Element { Skip "," Skip Element } ] Skip "]" Element = Value | (empty, producing a hole) ; one trailing comma is ignored, extra commas add holes Number = Sign* ( Decimal | "0x" Hex | "0o" Octal | "0b" Binary | "Infinity" | "NaN" ) Sign = "+" | "-" ; any number of them, spaces allowed Decimal = digits [ "." digits ] [ ("e"|"E") [Sign] digits ] | "." digits | digits "." ; "_" may appear among digits, see the numbers pageDetails the grammar compresses: an empty Element only occurs between commas or before the closing bracket, an unquoted key never decodes escape sequences, and esStrictCompatible narrows several productions (BareKey must then be an identifier or a number, signs may appear at most once, back-tick keys are rejected, and quoted strings may not contain a raw line terminator). Those narrowings are listed on the pages that own each production.
Errors and where they point
Since 1.1.6 the thrown Error message includes a [line:column] suffix and a few characters of context with the offending character in square brackets. Common messages include "Two values with no separator between them", "Object field name with no value", "Incomplete string", "Invalid number", "Sign with no number following", "Incomplete keyword" and "bad context; excessive commas". The error reference and parse error troubleshooting pages map each message to a fix.
The esStrictCompatible subset
Passing { esStrictCompatible: true } as the third argument to JSON6.parse narrows the accepted syntax to a subset of ECMAScript strict mode, so that anything that parses could also be pasted into a module. We verified each rejection the README lists.
| Input | Default | esStrictCompatible |
|---|---|---|
0123 | 123 | throws |
"\012" | NUL followed by 12 | throws |
"\8" | 8 | throws |
"a<LF>b" | string with newline | throws (back-tick strings still allowed) |
{`a`: 1} | {a: 1} | throws |
{a-b: 1} | {'a-b': 1} | throws |
--5 | 5 | throws |
+5 | 5 | 5 (single sign is fine) |
[1,,2] | hole | still accepted |
undefined | undefined | still accepted |
0o17 | 15 | still accepted |
Notice what the option does not do. It does not forbid empty array members, undefined, the extra literal forms, or unknown escapes such as "\q", because those are valid ECMAScript. The option is about "does this text mean the same thing in JavaScript?", not about being JSON-strict, and it will not make a file parseable by a JSON parser.
FAQ
Can a JSON6 file hold more than one value?
Not with JSON6.parse, which returns only the first and ignores the rest without an error. Use JSON6.begin for a stream of values separated by whitespace or newlines.
Are # comments allowed in JSON6?
No. The README has a to-do about them, but json-6 1.1.7 throws on a hash character. Only // and /* */ work.
Is undefined a valid JSON6 value?
Yes. It is a keyword, so {a: undefined} and [undefined] parse, and JSON6.parse("undefined") returns undefined. Strict JSON has no equivalent.
Does JSON6 allow a BOM at the start of a file?
Yes. U+FEFF is in the parser's whitespace list, so a leading byte order mark is skipped.
Why does an em space break my file?
The parser accepts a fixed list of whitespace code points and does not accept the general Unicode space category, so U+2003 and U+3000 throw even though JSON5 and ECMAScript accept them. Replace them with ordinary spaces.
Test the syntax in your browser
Check any of the inputs on this page with the online validator.