Getting Started with JSON6
Install json-6, write a commented .json6 file, parse it and load it from Node in about ten minutes.
What you will do: Install json-6, write a .json6 file with comments and new number formats, parse it with JSON6.parse, load it with the require hook, and convert it to JSON with the CLI. Every example here was run, and the output shown is real.
What JSON6 Is and How to Install It
JSON6 is an extension of JSON5 created by d3x0r. It reads JSON5 and, through it, JSON, and adds a few things JSON5 lacks: back-tick strings, multi-line strings in every quote style, 0b and 0o number literals, underscore separators, empty array members and the undefined keyword. It adds no new data types, and the author says plainly that it is not an official successor to JSON. Files use the .json6 extension. The full list is on the syntax page.
The reference implementation is the json-6 package on npm (MIT license, no dependencies). Install it like any other package:
npm install json-6 Note the hyphen. The npm package named json6 (no hyphen) is an unrelated 2015 prototype that has not been updated since. The current parser is json-6, version 1.1.7 as of 10-16-2026.
The package declares support for Node 10 and later. Everything in this tutorial was run on Node 24. It works in browsers too, but this guide stays on Node; the browser page covers the other side.
Write Your First .json6 File
Create settings.json6. Anything valid in JSON works, so you can start from an existing config and add features one at a time. This file uses most of the common ones:
// settings.json6 - my first JSON6 file { name: 'demo-app', version: "1.0.0", debug: true, // line comment /* block comment */ retries: 0x0A, // hexadecimal mask: 0b1010_1010, // binary, with a separator ratio: .75, tags: ['a', 'b', 'c',], note: `back-tick strings can span lines`, } Comments, trailing commas and unquoted keys come from JSON5. The binary literal with its underscore separator and the multi-line back-tick string are JSON6 additions. A back-tick string keeps its newlines exactly as written, and unlike a JavaScript template literal it never evaluates ${...}.
Parse It
JSON6.parse takes text and returns a value, exactly like JSON.parse. It also accepts a reviver as the second argument. Read the file yourself and hand it the string:
const fs = require('node:fs'); const JSON6 = require('json-6'); const settings = JSON6.parse(fs.readFileSync('settings.json6', 'utf8')); console.log(settings);{ name: 'demo-app', version: '1.0.0', debug: true, retries: 10, mask: 170, ratio: 0.75, tags: [ 'a', 'b', 'c' ], note: 'back-tick\nstrings can span lines' }Every extension was resolved to an ordinary value: the hex literal is 10, the binary literal is 170, the comments are gone, and the trailing commas are ignored. What you get back is a plain JavaScript object, so the rest of your program does not need to know the file was JSON6.
The third argument is an options object. { esStrictCompatible: true } restricts the grammar to what a JavaScript engine would also accept, { forbidTemplateSubstitution: true } rejects ${ inside back-tick strings, and { normalizeNumericKeys: true } makes a key like 1e3 become "1000". All of them are off by default. The config files tutorial shows when to turn them on.
Parsing stops after the first value. JSON6.parse returns once it has one complete value and silently ignores anything after it. That is convenient for streams and dangerous for config files; see problems that do not raise an error.
Write It Back with stringify
JSON6.stringify(value, replacer, space, options) mirrors JSON.stringify and adds a fourth options argument. Its output is JSON6 text, not JSON:
const fs = require('node:fs'); const JSON6 = require('json-6'); const settings = JSON6.parse(fs.readFileSync('settings.json6', 'utf8')); console.log(JSON6.stringify(settings)); console.log(JSON6.stringify(settings, null, 2, { sortKeys: false }));{debug:true,mask:170,name:"demo-app",note:"back-tick strings can span lines",ratio:0.75,retries:10,tags:["a","b","c"],version:"1.0.0"} { name: "demo-app", version: "1.0.0", debug: true, retries: 10, mask: 170, ratio: 0.75, tags: [ "a", "b", "c" ], note: "back-tick strings can span lines" } Three behaviors are worth knowing before you rely on it. Keys are sorted alphabetically by default, which is why the first line starts with debug and not name; pass { sortKeys: false } to keep insertion order. Keys that are valid identifiers are written bare, and the rest are quoted. And a string containing a newline is written with the raw newline inside the quotes, which is valid JSON6 but not valid JSON.
Do not use JSON6.stringify to produce files that other tools read as JSON. Use JSON.stringify for that. Also note that JSON6.stringify does not call toJSON, so a Date is written as {}, and comments in the original file are not preserved, because the parser discards them.
Load .json6 Files Directly
Reading and parsing by hand is fine, but Node can load .json6 files the way it loads .json. For CommonJS, require the hook once, then require the file:
require('json-6/lib/require'); // registers the .json6 extension const settings = require('./settings.json6'); console.log(settings.name, settings.retries);demo-app 10 For ES modules, register the loader with the --import flag (Node 20.6 or later). The module you import has the parsed data as its default export:
import settings from './settings.json6'; console.log(settings.name, settings.retries);node --import json-6/lib/register.mjs app.mjsdemo-app 10 On older Node versions the loader is enabled with --experimental-loader json-6/lib/import.mjs instead. Bundlers such as webpack, Rollup and esbuild do not know the extension; for those, read the file as text and call JSON6.parse yourself. Importing the package itself in an ES module gives only a default export, so write import JSON6 from 'json-6', not import { parse } from 'json-6'.
Convert to JSON from the command line
The package installs a json-6 command with one feature: json-6 -c file.json6 writes a sibling file.json with four-space indentation. It is how the package builds its own package.json from package.json6, and it is the right tool when a downstream program insists on plain JSON.
npx json-6 -c settings.json6{ "name": "demo-app", "version": "1.0.0", "debug": true, "retries": 10, "mask": 170, "ratio": 0.75, "tags": [ "a", "b", "c" ], "note": "back-tick\nstrings can span lines" } The comments are gone, the hex and binary numbers are now decimal, and the multi-line string became an escaped \n. The conversion goes through the JavaScript value, so anything JSON cannot hold is lost: Infinity and NaN become null, undefined values vanish, and empty array members become null. The CLI page has more.
A Quick Tour of What Parses
Each row below was parsed with JSON6.parse; the middle column is what Node prints for the result.
| JSON6 text | Parsed value | Feature |
|---|---|---|
0xFF | 255 | hexadecimal |
0b1010_1010 | 170 | binary with separator |
0o17 | 15 | octal |
1_000_000 | 1000000 | numeric separator |
0123 | 123 | leading zeros (decimal, not octal) |
.5 | 0.5 | leading decimal point |
+7 | 7 | explicit plus sign |
--5 | 5 | repeated signs |
Infinity | Infinity | Infinity |
[1,,3] | [ 1, <1 empty item>, 3 ] | empty array member |
"\u{41}" | 'A' | braced unicode escape |
`a${b}` | 'a${b}' | back-tick string, no substitution |
{a-b: 1} | { 'a-b': 1 } | punctuation in a bare key |
{'k': 1, `j`: 2} | { k: 1, j: 2 } | quoted and back-tick keys |
Two rows deserve a second look. 0123 is the decimal number 123: JSON6 deliberately allows leading zeros so that columns of numbers can be aligned. A JavaScript engine in sloppy mode would read the same digits as octal 83, which is the main reason the esStrictCompatible option exists. And [1,,3] produces a sparse array with a hole at index 1; convert it with JSON.stringify and the hole becomes null.
When Something Is Wrong
Invalid input throws, and the thrown value deserves a look now because it differs from JSON.parse in two ways:
const JSON6 = require('json-6'); try { JSON6.parse("{ port: 8080 host: 'localhost' }"); } catch (err) { console.log(err instanceof SyntaxError); console.log(err.name); console.log(err.message); }false Error fault parsing 'h' unexpected at 14 (near '80 [h]ost: 'loca') [1:14] The error is a plain Error, not a SyntaxError, so do not filter on the class. The line and column are at the end of the message in brackets, and the character the parser objected to is the one inside the square brackets in the near excerpt. Here the parser was happy with 8080, then found host where a comma should be. The parse errors guide shows how to turn this into a pointer under the offending line, and the error reference lists every message.
Parsing a Stream
JSON6.begin(callback) returns a parser you feed with write(). Values are passed to the callback as soon as each one is complete, even if the text arrives in arbitrary chunks. That makes it suitable for sockets and large log files made of many concatenated values:
const JSON6 = require('json-6'); const parser = JSON6.begin((value) => console.log('got', value)); parser.write('{ a: 1 } { b: '); // one complete value, one still open parser.write('2 } [3, 4]'); // finishes the object, then an array parser.write(''); // flush anything still pendinggot { a: 1 } got { b: 2 } got [ 3, 4 ] Be careful about using the stream to validate a whole document: a dangling piece at the end (a lone {, or an unclosed container that does not end in a number) is dropped without an error, so use parse() for single documents. The streaming page covers the details. After write() throws, the parser refuses more input until you call reset().
Where to Go Next
- Move an existing project: migrate from JSON or migrate from JSON5.
- Build something real: the config file loader adds validation and environment overrides.
- Learn the rules: the syntax reference and cheat sheet.
- Use TypeScript: the package ships its own type declarations, covered on the TypeScript page.
FAQ
Is a .json6 file valid JSON?
Not in general. Every valid JSON document parses as JSON6, but the reverse is false as soon as a file uses a comment, a bare key or any other extension. That is why the project uses the separate .json6 extension.
What is the difference between json6 and json-6 on npm?
json-6 is the maintained parser (1.1.7, published 10-16-2026). json6 is a 2015 prototype by the same author and is not the one to install.
Does JSON6 work in the browser?
Yes. The package has a browser build, and the same JSON6.parse API applies. See the browser page for how to load it.
Should I use JSON6 or JSON5?
JSON5 has far more tooling and implementations. JSON6 reads all JSON5 and adds a few conveniences, but only one maintained parser exists. The comparison page weighs the trade-off.
Ready to Move a Real Project?
Follow a migration guide, or build a config loader that validates its input.