Когда строгий JSON заставляет вас отлаживать код глубоко за полночь из-за одной пропущенной запятой, пора познакомиться с его более лояльными собратьями — JSON5 и JSON with Comments (JSONC).
Что такое JSON5?
JSON5 — это расширение JSON, заимствующее возможности из ECMAScript 5.1: ключи без кавычек, замыкающие запятые, строки в одинарных кавычках, комментарии и шестнадцатеричные числа. Формат поддерживается сообществом и предназначен для того, чтобы конфигурационные файлы, написанные вручную, были читабельнее и прощали мелкие ошибки в большей степени, чем строгий JSON.
Что такое JSONC?
JSONC (JSON with Comments) — минимальное расширение стандартного JSON, добавляющее поддержку однострочных (//) и многострочных (/* */) комментариев. Допустимы ли в нём замыкающие запятые, зависит от парсера. JSONC используется как нативный формат настроек VS Code, файла tsconfig.json и других конфигурационных файлов TypeScript.
Зачем нужен «лояльный» JSON
- Узкие места читаемости: стандартный JSON запрещает комментарии, замыкающие запятые, одинарные кавычки и так далее, что мешает ясности в конфигах и демонстрационных файлах.
- Боль командной работы: гигантские JSON-файлы без подсказок поддерживать тяжело, и одно мелкое изменение может сломать всё.
- Реалии DevOps: Kubernetes и CI/CD-пайплайны часто на лету объединяют или генерируют JSON; лояльный синтаксис резко сокращает ручные правки.
JSON5 и JSONC — обзор
| Возможность | JSON (RFC 8259) | JSONC | JSON5 |
|---|---|---|---|
Комментарии // и /* */ | Нет | Да | Да |
| Замыкающие запятые | Нет | Зависит от парсера (см. ниже) | Да, одна на объект или массив |
| Ключи без кавычек | Нет | Нет | Да |
| Строки в одинарных кавычках | Нет | Нет | Да |
| Перенос строкового литерала на новую строку (экранированный перевод строки) | Нет | Нет | Да |
Шестнадцатеричные числа (0x1F) | Нет | Нет | Да |
.5, 5., ведущий + | Нет | Нет | Да |
Infinity, NaN | Нет | Нет | Да |
Двоичные числа (0b101) | Нет | Нет | Нет |
| Спецификация | RFC 8259 / ECMA-404 | Формального стандарта нет; на практике формат определяют VS Code и jsonc-parser | Спецификация JSON5 1.0.0 |
Читается встроенными JSON.parse / json.loads | Да | Нет | Нет |
Источники: спецификация JSON5, документация VS Code по JSON и RFC 8259. Строку про двоичные числа мы проверили сами: JSON5.parse('{a: 0b101}') с json5 2.2.3 завершается ошибкой JSON5: invalid character 'b' at 1:6.
Одной фразой: JSON5 ощущается как литерал JavaScript-объекта, а JSONC — это обычный JSON, который терпит комментарии: ключи и строки в нём по-прежнему берутся в двойные кавычки.
Замыкающие запятые в JSONC зависят от парсера
Официальной спецификации у JSONC нет. Microsoft неформально ввела формат для конфигурационных файлов VS Code и выпустила вместе с ним jsonc-parser. Черновик сообщества на jsonc.org пытается формализовать JSONC, но и там сказано лишь, что парсеры «MAY support trailing commas» (могут поддерживать замыкающие запятые). На практике инструменты ведут себя по-разному:
| Парсер или инструмент | Замыкающая запятая | Источник |
|---|---|---|
| VS Code, режим JSON with Comments | Принимается, но с предупреждением | Документация VS Code |
jsonc-parser 3.3.1, параметры по умолчанию | Отмечается ошибками PropertyNameExpected / ValueExpected, но значение всё равно возвращается | Запуск ниже |
jsonc-parser 3.3.1, allowTrailingComma: true | Принимается | Запуск ниже |
TypeScript 5.9.3 (tsc -p) | Принимается | Запуск на примере tsconfig.json ниже |
Deno (deno.jsonc) | Принимается | Документация Deno по конфигурации |
Если файл должен читаться любым парсером JSONC, обходитесь без замыкающих запятых.
Примеры синтаксиса
Чистый JSON (строгий)
{
"name": "Go Tools",
"features": ["Base64", "JSON Formatter"]
}
Пример JSON5
Файл config.json5:
// конфиг для разработки
{
name: 'go-tools',
port: 0x1F90, // 8080 в шестнадцатеричной записи
tags: ['json', 'json5',],
}
Пример JSONC
Файл tsconfig.json:
{
// строгая проверка типов
"compilerOptions": {
"strict": true,
"target": "ES2022", /* современный синтаксис на выходе */
},
"include": ["src"],
}
Как определить формат файла
По одному расширению этого не понять: файл .json вполне может разбираться как JSONC или JSON5. Сверьтесь с таблицей, а затем с документацией инструмента, который читает файл.
| Файл | Формат | Примечание | Источник |
|---|---|---|---|
tsconfig.json, jsconfig.json, tsconfig.*.json | JSONC | VS Code открывает их в режиме JSONC; tsc 5.9.3 принимает комментарии и замыкающие запятые | Исходный код VS Code (typescript-basics), наш запуск |
.vscode/settings.json, tasks.json, launch.json | JSONC | Перечислены в документации как файлы JSON with Comments | Документация VS Code |
devcontainer.json | JSONC | Спецификация называет его «a JSON with Comments file» (файл формата JSON with Comments) | Спецификация Dev Container |
deno.jsonc | JSONC | «with deno.jsonc you can add comments and trailing commas» (в deno.jsonc можно добавлять комментарии и замыкающие запятые) | Документация Deno |
babel.config.json, .babelrc.json | JSON5, несмотря на расширение .json | Babel разбирает их как JSON5; VS Code подсвечивает их как JSONC | Документация Babel, исходный код VS Code |
renovate.json5, .renovaterc.json5 | JSON5 | renovate.json тоже принимает JSONC | Документация Renovate |
Любой файл *.json5 | JSON5 | — | — |
package.json | Строгий JSON | npm: «It must be actual JSON, not just a JavaScript object literal.» (это должен быть настоящий JSON, а не просто литерал JavaScript-объекта) | Документация npm, наш запуск |
Файл babel.config.json5 Babel не ищет: расширения .json5 нет среди документированных. Как JSON5 он читает именно варианты с расширением .json.
Сообщения об ошибках — дословно
Мы передали каждой среде выполнения два небольших файла. В comment.json есть комментарий:
{
// порт dev-сервера
"port": 8080
}
В trailing.json — замыкающая запятая:
{
"port": 8080,
}
Node.js 26.10.0, JSON.parse (Chrome Headless Shell 156 выдаёт тот же текст, поскольку оба работают на V8):
comment.json -> SyntaxError: Expected property name or '}' in JSON at position 4 (line 2 column 3)
trailing.json -> SyntaxError: Expected double-quoted property name in JSON at position 18 (line 3 column 1)
Python 3.13.5, json.loads:
comment.json -> json.decoder.JSONDecodeError: Expecting property name enclosed in double quotes: line 2 column 3 (char 4)
trailing.json -> json.decoder.JSONDecodeError: Illegal trailing comma before end of object: line 2 column 15 (char 16)
jq 1.7:
comment.json -> jq: parse error: Invalid numeric literal at line 2, column 5
trailing.json -> jq: parse error: Expected another key-value pair at line 3, column 1
npm 11.19.1, со строкой // comment в package.json:
npm error code EJSONPARSE
npm error JSON.parse Invalid package.json: JSONParseError: Expected property name or '}' in JSON at position 4 (line 2 column 3) while parsing near "{\n // comment\n \"name\":..."
npm error JSON.parse Failed to parse JSON data.
npm error JSON.parse Note: package.json must be actual JSON, not just JavaScript.
Как их читать:
position 4 (line 2 column 3)указывает на первый/комментария. Если ошибка приходится на начало строки, которая начинается с//или/*, перед вами почти наверняка JSONC или JSON5.- На замыкающей запятой V8 и Python указывают на разные места. V8 сообщает о закрывающей
}(строка 3), а Python 3.13.5 — о самой запятой (строка 2, столбец 15). В других версиях формулировки могут отличаться; текст выше — ровно то, что вывели эти версии. - Если в сообщении процитирован невидимый символ, как в выводе Node 26
Unexpected token '', "{}" is not valid JSON(в обоих местах внутри кавычек на самом деле стоит невидимый U+FEFF), скорее всего, файл начинается не с комментария, а с невидимой метки порядка байтов (BOM). Подробнее — в статье UTF-8 BOM и ошибки JSON.parse.
Конвертация JSONC и JSON5 в стандартный JSON
При конвертации пропадают все комментарии: в JSON для них просто нет места. Поэтому исходником остаётся файл с комментариями, а .json на выходе стоит считать сгенерированным артефактом.
Node.js: из JSON5 в JSON с помощью json5
// json5-to-json.mjs (установка: npm install json5)
import { readFileSync, writeFileSync } from 'node:fs';
import JSON5 from 'json5';
const data = JSON5.parse(readFileSync('config.json5', 'utf8'));
writeFileSync('config.json', JSON.stringify(data, null, 2) + '\n');
Если запустить скрипт с json5 2.2.3 на примере JSON5 выше, config.json получится таким:
{
"name": "go-tools",
"port": 8080,
"tags": [
"json",
"json5"
]
}
Node.js: из JSONC в JSON с помощью jsonc-parser
jsonc-parser — парсер JSON с комментариями от Microsoft. Его parse() не выбрасывает исключений при синтаксических ошибках: проблемы он складывает в массив errors и всё равно возвращает значение, насколько удалось его разобрать. Поэтому массив нужно проверять самостоятельно:
// jsonc-to-json.mjs (установка: npm install jsonc-parser)
import { readFileSync } from 'node:fs';
import { parse, printParseErrorCode } from 'jsonc-parser';
const errors = [];
const data = parse(readFileSync('tsconfig.json', 'utf8'), errors, {
allowTrailingComma: true,
});
if (errors.length > 0) {
for (const e of errors) console.error(printParseErrorCode(e.error), 'at offset', e.offset);
process.exit(1);
}
console.log(JSON.stringify(data, null, 2));
С jsonc-parser 3.3.1 и примером tsconfig.json выше скрипт выводит чистый JSON и завершается с кодом 0. Без allowTrailingComma: true тот же файл даёт ошибки PropertyNameExpected и ValueExpected на }, которая стоит сразу после каждой замыкающей запятой.
Python: пакет json5
В модуле json из стандартной библиотеки нет опции для комментариев. Пакет json5 читает JSON5, а значит, и JSONC: комментарии и замыкающие запятые в JSON5 допустимы.
# установка: pip install json5
import json
import json5
with open("tsconfig.json", encoding="utf-8") as f:
data = json5.load(f)
print(json.dumps(data, indent=2, ensure_ascii=False))
Проверено на Python 3.13.5 и json5 0.17.3: скрипт выводит тот же JSON, что и версия для Node.
Командная строка: CLI json5
В npm-пакет json5 входит CLI, который конвертирует файл в JSON и проверяет синтаксис. JSONC-файлы он тоже читает:
npx json5 config.json5 # компактный JSON в stdout
npx json5 -s 2 -o config.json config.json5 # с отступами, запись в файл
npx json5 -v tsconfig.json # только проверка; код выхода 1 при синтаксической ошибке
Поскольку с -v команда при синтаксической ошибке завершается с кодом 1, её можно в том же виде использовать как шаг CI, который проверяет JSON5- и JSONC-файлы, отредактированные вручную.
jq здесь не поможет: как видно выше, jq 1.7 останавливается на первом же комментарии.
Осторожно с Infinity и NaN
JSON5 допускает Infinity и NaN, но в JSON их записать нельзя, и в двух языках это решается по-разному:
JSON.stringify(JSON5.parse('{a: Infinity, b: NaN}'));
// '{"a":null,"b":null}' (молча превращается в null)
json.dumps(json5.loads('{a: Infinity, b: NaN}'))
# '{"a": Infinity, "b": NaN}' (такой вывод не является валидным JSON)
json.dumps(json5.loads('{a: Infinity}'), allow_nan=False)
# ValueError: Out of range float values are not JSON compliant: inf
Если в JSON5-файле могут встретиться эти значения, в Python передавайте allow_nan=False или проверяйте их наличие до конвертации. Строки JSON5 в одинарных кавычках, содержащие " или обратные слеши, JSON.stringify экранирует заново. Правила описаны в руководстве по экранированию строк JSON.
Проверка получившегося JSON
После конвертации вставьте результат в форматировщик JSON, чтобы проверить его и привести к читаемому виду (pretty-print). Инструмент работает в браузере.
Учтите: форматировщик принимает только строгий JSON. Он разбирает ввод браузерным JSON.parse, поэтому JSONC- или JSON5-файл, вставленный как есть, выдаст синтаксическую ошибку с номером строки и столбца, на которых остановился разбор. Сначала конвертируйте, потом проверяйте.
Когда JSONC и JSON5 не подходят
- Payload в API и обмен данными. В RFC 8259 сказано, что генератор JSON «MUST strictly conform to the JSON grammar» (обязан строго соответствовать грамматике JSON). На принимающей стороне обычно стоит
JSON.parseилиjson.loads, и оба отвергают комментарии. package.json. npm требует строгий JSON. Достаточно одного комментария, чтобы команды npm вродеnpm runпадали сEJSONPARSE.- Файлы, которые читают инструменты вне вашего контроля.
require('./tsconfig.json')в Node использует строгий парсер JSON и падает на tsconfig с комментариями (SyntaxError: …tsconfig.json: Expected property name or '}' in JSON at position 4). Любому скрипту, который читает JSONC-файл, нужен парсер JSONC. - Файл
.json, который незаметно стал JSONC. Документация Renovate рекомендует файл.jsoncвместо.jsonс комментариями, поскольку последний «can cause issues with editors and syntax highlighting» (может вызывать проблемы с редакторами и подсветкой синтаксиса). Явное расширение сразу сообщает любому инструменту, чего ожидать.
Если формат конфигурации выбирается с нуля и комментарии нужны везде, присмотритесь к TOML и YAML: они поддерживают комментарии нативно. Сравнение — в статье TOML vs JSON vs YAML.
Реальные конфигурационные файлы
JSON5 и JSONC уже широко используются в конфигурационных файлах, с которыми вы сталкиваетесь ежедневно. Ниже — конкретные примеры:
TypeScript (tsconfig.json — JSONC)
{
// Строгий режим ловит больше ошибок на этапе компиляции
"compilerOptions": {
"strict": true,
"target": "ES2022",
"module": "ESNext",
"outDir": "./dist",
// Алиасы путей делают импорты чище
"paths": {
"@/*": ["./src/*"],
"@tests/*": ["./tests/*"],
},
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"],
}
tsconfig.json в TypeScript нативно использует JSONC — комментарии и замыкающие запятые работают «из коробки». Это один из самых распространённых JSONC-файлов в любом JavaScript- или TypeScript-проекте.
Babel (babel.config.json — JSON5)
Babel разбирает babel.config.json и .babelrc.json как JSON5, поэтому ключи без кавычек и одинарные кавычки там работают.
{
// Одинарные кавычки и ключи без кавычек делают конфиг читабельнее
presets: [
['@babel/preset-env', {
targets: '> 0.25%, not dead',
modules: false, // Отдадим модули сборщику
}],
],
plugins: [
'@babel/plugin-transform-runtime',
],
}
Настройки рабочей области VS Code (.vscode/settings.json — JSONC)
{
// Настройки редактора
"editor.fontSize": 14,
"editor.tabSize": 2,
"editor.formatOnSave": true,
// Переопределения по языку
"[typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode",
},
"[jsonc]": {
"editor.defaultFormatter": "esbenp.prettier-vscode",
},
}
Практические советы и оговорки
1. Конвертируйте перед продакшеном
Браузеры по-прежнему требуют строгий JSON для JSON.parse. Конвертируйте конфиги на этапе сборки, как показано выше в разделе о конвертации в стандартный JSON.
2. Безопасность и надёжность
Лояльность может скрывать «лишние» поля. Всегда валидируйте конфигурацию через JSON Schema или zod, прежде чем её применять. И при работе со snapshot-тестами помните: разница JSON5 / JSONC между запусками часто «шумит» на полях вроде timestamp, requestId и UUID — практические паттерны игнорирования таких полей разобраны в гайде по игнорированию timestamp и ID при JSON diff. Если в проекте параллельно лежат YAML-конфиги, особенно для Kubernetes — обратите внимание на «норвежскую проблему» YAML и различия JSON-YAML: безкавычные значения вроде no и off тихо превращаются в boolean.
// Проверяем форму конфига через zod после разбора
import { readFileSync } from 'node:fs';
import { z } from 'zod';
import JSON5 from 'json5';
const ConfigSchema = z.object({
port: z.number().min(1).max(65535),
host: z.string(),
debug: z.boolean().default(false),
});
const raw = JSON5.parse(readFileSync('config.json5', 'utf8'));
const config = ConfigSchema.parse(raw); // Бросит ошибку при несоответствии
3. Командные соглашения
- В README объявите, что
*.json5— только для конфигов; пакеты для релиза должны поставляться со строгим.json. - Стандартизируйте правила Prettier, чтобы избежать «шумных» диффов.
- Используйте
.editorconfigдля согласованных отступов в JSON, JSON5 и JSONC.
4. Производительность
Разбор JSON5/JSONC добавляет зависимости и небольшой оверхед — приемлемо для CLI и dev-инструментов, но в продакшене всё нужно измерять. Для конфигурационных файлов, загружаемых один раз при старте, это незаметно. На горячих путях, где разбираются тысячи объектов в секунду, придерживайтесь строгого JSON.
Часто задаваемые вопросы
В чём разница между JSON5 и JSONC?
JSONC — это стандартный JSON плюс комментарии // и /* */; допустимы ли замыкающие запятые, зависит от парсера. JSON5 идёт дальше и добавляет синтаксис ES5.1: ключи без кавычек, одинарные кавычки, hex-числа, Infinity/NaN и замыкающие запятые. Корректный JSONC-файл обычно является и корректным JSON5, но не наоборот. Выбирайте JSONC для конфигов, где достаточно комментариев, и JSON5, когда нужен более богатый синтаксис.
Можно ли использовать JSON5 или JSONC в продакшен-API?
Нет — JSON5 и JSONC спроектированы для конфигурационных файлов, а не для обмена данными. В API следует использовать стандартный JSON (RFC 8259) для максимальной совместимости. Оставьте JSON5/JSONC для локальных конфигов вроде tsconfig.json, .vscode/settings.json или конфигурации окружения, где читаемость для человека важнее, чем удобство машины.
VS Code поддерживает JSON5 нативно?
Без расширений — нет. Встроенное расширение JSON в VS Code регистрирует такие языки, как json, jsonc и jsonl, но не json5, поэтому для подсветки файлов .json5 нужно расширение из маркетплейса. JSONC, напротив, поддерживается «из коробки»: настройки, tasks.json, launch.json и tsconfig.json открываются в режиме JSON with Comments.
Как конвертировать JSON5 в стандартный JSON?
Используйте npm-пакет json5: JSON5.parse() читает JSON5, затем JSON.stringify() выводит стандартный JSON. Для CLI: npx json5 < input.json5 > output.json. Комментарии при этом пропадают, а Infinity и NaN после JSON.stringify превращаются в null. Онлайн-инструменты, например наш JSON Formatter, помогут проверить корректность результата.
JSONC — это то же самое, что «JSON with Comments»?
Да — JSONC расшифровывается как «JSON with Comments»: так называется языковой режим VS Code, а jsonc — его идентификатор языка и расширение файлов. Формального стандарта нет, на jsonc.org опубликован черновик сообщества, основанный на том, что jsonc-parser принимает по умолчанию. К стандартному JSON формат добавляет комментарии // и /* */, а поддержка замыкающих запятых зависит от парсера. Парсеры удаляют комментарии до обработки, поэтому итоговая структура данных идентична стандартному JSON.
Подборка браузерных инструментов разработчика, включая кодирование Base64, генерацию хешей и конвертацию timestamp, разобрана в подборке базовых инструментов разработчика.
Итог
Поиск баланса между читаемостью и строгостью — классическая дилемма разработчика. JSON5 и JSONC улучшают опыт написания, и при правильно настроенном пайплайне сборки и валидации можно безопасно пользоваться преимуществами «лояльного JSON».