Skip to content
Powrót do bloga
Poradniki

JSON5 i JSONC: bardziej wyrozumiały sposób formatowania JSON

Poznaj różnice między JSON5 a JSONC, formatuj pliki konfiguracyjne z komentarzami i wpinaj formatery do pipeline'u CI — z praktycznymi przykładami kodu.

9 min czytania

Kiedy ścisły JSON każe debugować do późnej nocy z powodu jednego brakującego przecinka, najwyższy czas poznać jego bardziej wyrozumiałych krewnych — JSON5 oraz JSON with Comments (JSONC).

Czym jest JSON5?

JSON5 to rozszerzenie JSON, które przejmuje funkcje z ECMAScript 5.1, w tym klucze bez cudzysłowów, przecinki kończące, łańcuchy w pojedynczych cudzysłowach, komentarze oraz liczby szesnastkowe. Format jest rozwijany przez społeczność i został zaprojektowany tak, aby ręcznie pisane pliki konfiguracyjne były czytelniejsze i bardziej wyrozumiałe niż w przypadku ścisłego JSON.

Czym jest JSONC?

JSONC (JSON with Comments) to minimalne rozszerzenie standardowego JSON, które dodaje obsługę komentarzy jednoliniowych (//) i wieloliniowych (/* */). To, czy dopuszcza także przecinki kończące, zależy od parsera. Pełni funkcję natywnego formatu dla ustawień VS Code, plików tsconfig.json oraz innych plików konfiguracyjnych TypeScript.

Po co nam „wyrozumiały” JSON

  • Bariery czytelności: Standardowy JSON zabrania komentarzy, przecinków kończących, pojedynczych cudzysłowów itd., co utrudnia zrozumienie konfiguracji i przykładów.
  • Trudność współpracy w zespole: Ogromne pliki JSON bez żadnych adnotacji są trudne w utrzymaniu; drobna edycja może uszkodzić cały plik.
  • Realia DevOps: Kubernetes oraz pipeline’y CI/CD często łączą lub generują JSON w locie; wyrozumiała składnia mocno ogranicza ręczne poprawki.

JSON5 a JSONC — szybkie porównanie

CechaJSON (RFC 8259)JSONCJSON5
Komentarze // i /* */NieTakTak
Przecinki kończąceNieZależy od parsera (zob. niżej)Tak, jeden na obiekt lub tablicę
Klucze bez cudzysłowówNieNieTak
Łańcuchy w pojedynczych cudzysłowachNieNieTak
Łańcuchy w kilku wierszach (escapowany znak nowego wiersza)NieNieTak
Liczby szesnastkowe (0x1F)NieNieTak
.5, 5., wiodący +NieNieTak
Infinity, NaNNieNieTak
Liczby w systemie dwójkowym (0b101)NieNieNie
SpecyfikacjaRFC 8259 / ECMA-404Brak formalnego standardu; w praktyce definiują go VS Code i jsonc-parserSpecyfikacja JSON5 1.0.0
Odczyt wbudowanym JSON.parse / json.loadsTakNieNie

Źródła: specyfikacja JSON5, dokumentacja JSON w VS Code i RFC 8259. Wiersz o liczbach dwójkowych sprawdziliśmy sami: JSON5.parse('{a: 0b101}') w json5 2.2.3 kończy się błędem JSON5: invalid character 'b' at 1:6.

W jednym zdaniu: JSON5 sprawia wrażenie literału obiektu JavaScript, podczas gdy JSONC to zwykły JSON, który toleruje komentarze — klucze i łańcuchy nadal muszą być w podwójnych cudzysłowach.

Przecinki kończące w JSONC zależą od parsera

JSONC nie ma oficjalnej specyfikacji. Microsoft wprowadził go nieformalnie na potrzeby plików konfiguracyjnych VS Code i równolegle wydał jsonc-parser. Społecznościowy szkic na jsonc.org próbuje ten format sformalizować, ale o przecinkach kończących mówi tylko tyle, że parsery „MAY support trailing commas” (mogą je obsługiwać). Narzędzia w praktyce zachowują się różnie:

Parser lub narzędziePrzecinek kończącyŹródło
VS Code, tryb JSON with CommentsAkceptowany, z ostrzeżeniemDokumentacja VS Code
jsonc-parser 3.3.1, opcje domyślneZgłaszany jako błędy PropertyNameExpected / ValueExpected, ale wartość i tak zostaje zwróconaTest niżej
jsonc-parser 3.3.1, allowTrailingComma: trueAkceptowanyTest niżej
TypeScript 5.9.3 (tsc -p)AkceptowanyTest na przykładowym tsconfig.json niżej
Deno (deno.jsonc)AkceptowanyDokumentacja konfiguracji Deno

Jeśli plik ma przyjąć każde narzędzie, które czyta JSONC, lepiej zrezygnować z przecinków kończących.

Przykłady składni

Klasyczny JSON (ścisły)

{
  "name": "Go Tools",
  "features": ["Base64", "JSON Formatter"]
}

Przykład JSON5

Plik JSON5, config.json5:

// konfiguracja deweloperska
{
  name: 'go-tools',
  port: 0x1F90,       // 8080 szesnastkowo
  tags: ['json', 'json5',],
}

Przykład JSONC

Plik JSONC, tsconfig.json:

{
  // ścisła kontrola typów
  "compilerOptions": {
    "strict": true,
    "target": "ES2022", /* nowoczesny kod wynikowy */
  },
  "include": ["src"],
}

Jak rozpoznać format pliku

Samo rozszerzenie niczego nie przesądza: plik .json może być parsowany jako JSONC albo JSON5. Najpierw warto sprawdzić poniższą tabelę, a potem dokumentację narzędzia, które ten plik czyta.

PlikFormatUwagiŹródło
tsconfig.json, jsconfig.json, tsconfig.*.jsonJSONCVS Code otwiera je w trybie JSONC; tsc 5.9.3 akceptuje komentarze i przecinki kończąceKod źródłowy VS Code (typescript-basics), nasz test
.vscode/settings.json, tasks.json, launch.jsonJSONCWymienione jako pliki JSON with CommentsDokumentacja VS Code
devcontainer.jsonJSONCSpecyfikacja nazywa go „a JSON with Comments file” (plik JSON with Comments)Specyfikacja Dev Container
deno.jsoncJSONC„with deno.jsonc you can add comments and trailing commas” (w deno.jsonc można dodawać komentarze i przecinki kończące)Dokumentacja Deno
babel.config.json, .babelrc.jsonJSON5, mimo rozszerzenia .jsonBabel parsuje je jako JSON5; VS Code podświetla je jako JSONCDokumentacja Babel, kod źródłowy VS Code
renovate.json5, .renovaterc.json5JSON5renovate.json przyjmuje też JSONCDokumentacja Renovate
Dowolny plik *.json5JSON5——
package.jsonŚcisły JSONnpm: „It must be actual JSON, not just a JavaScript object literal.” (musi to być prawdziwy JSON, a nie tylko literał obiektu JavaScript)Dokumentacja npm, nasz test

Babel nie szuka pliku babel.config.json5: rozszerzenia .json5 nie ma wśród tych, które opisuje jego dokumentacja. Jako JSON5 czyta właśnie warianty z rozszerzeniem .json.

Komunikaty błędów w dosłownym brzmieniu

Te same dwa małe pliki przekazaliśmy każdemu środowisku uruchomieniowemu. comment.json zawiera komentarz:

{
  // port serwera deweloperskiego
  "port": 8080
}

trailing.json ma przecinek kończący:

{
  "port": 8080,
}

Node.js 26.10.0, JSON.parse (Chrome Headless Shell 156 zwraca dokładnie ten sam tekst, bo oba korzystają z 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, z wierszem // comment w 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.

Jak je czytać:

  • position 4 (line 2 column 3) wskazuje pierwszy / komentarza. Jeśli błąd wypada na początku wiersza, który zaczyna się od // lub /*, plik jest niemal na pewno w formacie JSONC albo JSON5.
  • Przy przecinkach kończących V8 i Python wskazują różne miejsca. V8 zgłasza zamykający } (wiersz 3), a Python 3.13.5 sam przecinek (wiersz 2, kolumna 15). Inne wersje mogą formułować te komunikaty inaczej; powyższy tekst to dokładnie to, co wypisały wymienione wersje.
  • Jeśli komunikat cytuje znak, którego nie widać, jak w Node 26: Unexpected token '', "{}" is not valid JSON (w obu cudzysłowach siedzi w rzeczywistości niewidoczny znak U+FEFF), plik najpewniej zaczyna się od niewidocznego znacznika kolejności bajtów (BOM), a nie od komentarza. Więcej w artykule BOM UTF-8 a błędy JSON.parse.

Konwersja JSONC lub JSON5 do standardowego JSON

Konwersja usuwa wszystkie komentarze, bo JSON nie ma gdzie ich przechować. Plik z komentarzami warto traktować jako źródło, a wynikowy .json jako wygenerowany artefakt.

Node.js: JSON5 do JSON za pomocą json5

// json5-to-json.mjs (instalacja: 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');

Po uruchomieniu z json5 2.2.3 na przykładzie JSON5 z sekcji powyżej plik config.json wygląda tak:

{
  "name": "go-tools",
  "port": 8080,
  "tags": [
    "json",
    "json5"
  ]
}

Node.js: JSONC do JSON za pomocą jsonc-parser

jsonc-parser to parser Microsoftu dla JSON z komentarzami. Jego parse() nie rzuca wyjątku przy błędach składni. Problemy zbiera w tablicy errors i mimo to zwraca wartość odczytaną najlepiej, jak się da, więc tę tablicę trzeba sprawdzić samodzielnie:

// jsonc-to-json.mjs (instalacja: 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));

Z jsonc-parser 3.3.1 i przykładowym tsconfig.json z sekcji powyżej skrypt wypisuje czysty JSON i kończy działanie z kodem 0. Bez allowTrailingComma: true ten sam plik zgłasza PropertyNameExpected i ValueExpected na znaku } tuż po każdym przecinku kończącym.

Python: pakiet json5

Moduł json z biblioteki standardowej nie ma opcji obsługi komentarzy. Pakiet json5 czyta JSON5, a więc także JSONC, bo komentarze i przecinki kończące są w JSON5 dozwolone:

# instalacja: 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))

Przetestowano w Pythonie 3.13.5 z json5 0.17.3: skrypt wypisuje ten sam JSON co wersja dla Node.js.

Wiersz poleceń: CLI json5

Pakiet npm json5 zawiera CLI, które konwertuje do JSON i waliduje składnię. Czyta też pliki JSONC:

npx json5 config.json5                      # zwarty JSON na stdout
npx json5 -s 2 -o config.json config.json5  # z wcięciami, zapis do pliku
npx json5 -v tsconfig.json                  # tylko walidacja; kod wyjścia 1 przy błędzie składni

Ponieważ -v przy błędzie składni kończy działanie z kodem 1, to samo polecenie sprawdzi się jako krok CI, który kontroluje ręcznie edytowane pliki JSON5 lub JSONC.

jq tu nie pomoże: jak widać wyżej, jq 1.7 zatrzymuje się na pierwszym komentarzu.

Uwaga na Infinity i NaN

JSON5 dopuszcza Infinity i NaN, ale w JSON nie da się ich zapisać, a JavaScript i Python radzą sobie z tym inaczej:

JSON.stringify(JSON5.parse('{a: Infinity, b: NaN}'));
// '{"a":null,"b":null}'  (po cichu zamienia się w null)
json.dumps(json5.loads('{a: Infinity, b: NaN}'))
# '{"a": Infinity, "b": NaN}'  (wynik, który nie jest poprawnym JSON)
json.dumps(json5.loads('{a: Infinity}'), allow_nan=False)
# ValueError: Out of range float values are not JSON compliant: inf

Jeśli plik JSON5 może zawierać te wartości, w Pythonie warto przekazać allow_nan=False albo sprawdzić je przed konwersją. Łańcuchy JSON5 w pojedynczych cudzysłowach, które zawierają " lub ukośniki odwrotne, JSON.stringify escapuje na nowo. Zasady opisuje przewodnik po escapowaniu ciągów JSON.

Walidacja skonwertowanego JSON

Po konwersji wynik można wkleić do narzędzia Formatowanie JSON, aby go zwalidować i sformatować (pretty-print). Narzędzie działa w przeglądarce.

Uwaga: formater akceptuje wyłącznie ścisły JSON. Parsuje dane przeglądarkowym JSON.parse, więc plik JSONC lub JSON5 wklejony bez zmian kończy się błędem składni z numerem wiersza i kolumny, w których parsowanie się zatrzymało. Najpierw konwersja, potem walidacja.

Kiedy nie używać JSONC ani JSON5

  • Payload API i wymiana danych. RFC 8259 mówi, że generator JSON „MUST strictly conform to the JSON grammar” (musi ściśle przestrzegać gramatyki JSON). Po stronie odbiorcy zwykle działa JSON.parse lub json.loads, a oba odrzucają komentarze.
  • package.json. npm wymaga ścisłego JSON. Wystarczy jeden komentarz, by polecenia npm, takie jak npm run, kończyły się błędem EJSONPARSE.
  • Pliki czytane przez narzędzia, nad którymi nie ma się kontroli. require('./tsconfig.json') w Node.js używa ścisłego parsera JSON i zawodzi na tsconfig z komentarzami (SyntaxError: …tsconfig.json: Expected property name or '}' in JSON at position 4). Każdy skrypt, który czyta plik JSONC, potrzebuje parsera JSONC.
  • Plik .json, który po cichu stał się JSONC. Dokumentacja Renovate zaleca plik .jsonc zamiast pliku .json z komentarzami, bo ten drugi „can cause issues with editors and syntax highlighting” (może sprawiać problemy edytorom i podświetlaniu składni). Jawne rozszerzenie mówi każdemu narzędziu, czego się spodziewać.

Jeśli format konfiguracji wybiera się od zera, a komentarze mają działać wszędzie, TOML i YAML obsługują je natywnie. Więcej w porównaniu TOML vs JSON vs YAML.

Pliki konfiguracyjne w realnym świecie

JSON5 oraz JSONC są już szeroko używane w plikach konfiguracyjnych spotykanych na co dzień. Oto konkretne przykłady:

TypeScript (tsconfig.json — JSONC)

{
  // Strict mode catches more bugs at compile time
  "compilerOptions": {
    "strict": true,
    "target": "ES2022",
    "module": "ESNext",
    "outDir": "./dist",
    // Path aliases for cleaner imports
    "paths": {
      "@/*": ["./src/*"],
      "@tests/*": ["./tests/*"],
    },
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "dist"],
}

Plik tsconfig.json w TypeScript natywnie korzysta z JSONC — komentarze i przecinki kończące działają od razu. To jeden z najczęściej spotykanych plików JSONC w każdym projekcie JavaScript/TypeScript.

Babel (babel.config.json — JSON5)

Babel parsuje babel.config.json i .babelrc.json jako JSON5, więc klucze bez cudzysłowów i pojedyncze cudzysłowy działają w nich bez problemu.

{
  // Single quotes and unquoted keys make it more readable
  presets: [
    ['@babel/preset-env', {
      targets: '> 0.25%, not dead',
      modules: false,  // Let bundler handle modules
    }],
  ],
  plugins: [
    '@babel/plugin-transform-runtime',
  ],
}

Ustawienia obszaru roboczego VS Code (.vscode/settings.json — JSONC)

{
  // Editor preferences
  "editor.fontSize": 14,
  "editor.tabSize": 2,
  "editor.formatOnSave": true,

  // Language-specific overrides
  "[typescript]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode",
  },
  "[jsonc]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode",
  },
}

Praktyczne wskazówki i pułapki

1. Konwersja przed wdrożeniem na produkcję

Przeglądarki nadal wymagają ścisłego JSON dla JSON.parse. Konwersję warto więc wykonać na etapie builda, tak jak pokazano wyżej w sekcji o konwersji JSONC i JSON5 do standardowego JSON.

2. Bezpieczeństwo i niezawodność

Pobłażliwość może maskować nadmiarowe pola. Konfigurację należy zawsze walidować z użyciem JSON Schema lub zod, zanim zostanie ona zużyta:

// Validate config shape with zod after parsing
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); // Throws if invalid

3. Konwencje zespołowe

  • Warto zaznaczyć w README, że pliki *.json5 służą wyłącznie do konfiguracji; pakiety wydawane do publikacji powinny zawierać ścisłe .json.
  • Należy ustandaryzować reguły Prettier, aby ograniczyć szum w diffach.
  • Plik .editorconfig pomaga wymusić spójne wcięcia w plikach JSON, JSON5 oraz JSONC.

4. Wydajność

Parsowanie JSON5/JSONC dokłada zależności i lekki narzut — to do przyjęcia w narzędziach CLI i deweloperskich, ale na produkcji warto to zmierzyć. Dla plików konfiguracyjnych ładowanych raz przy starcie różnica jest pomijalna. Dla gorących ścieżek przetwarzających tysiące obiektów na sekundę lepiej pozostać przy ścisłym JSON.

Najczęściej zadawane pytania

Jaka jest różnica między JSON5 a JSONC?

JSONC to standardowy JSON z komentarzami // i /* */, a to, czy dopuszcza przecinki kończące, zależy od parsera. JSON5 idzie dalej i przejmuje składnię ES5.1: klucze bez cudzysłowów, pojedyncze cudzysłowy, liczby szesnastkowe, Infinity/NaN oraz przecinki kończące. Poprawny plik JSONC jest zwykle poprawnym plikiem JSON5, ale nie na odwrót. JSONC wybierze się do plików konfiguracyjnych, gdzie wystarczą komentarze; JSON5 sprawdzi się tam, gdzie potrzeba bogatszej składni.

Czy można używać JSON5 lub JSONC w produkcyjnych API?

Nie — JSON5 i JSONC są przeznaczone do plików konfiguracyjnych, a nie do wymiany danych. API powinny korzystać ze standardowego JSON (RFC 8259), aby zapewnić maksymalną interoperacyjność. JSON5/JSONC warto zarezerwować dla lokalnych plików konfiguracyjnych takich jak tsconfig.json, .vscode/settings.json lub konfiguracji środowiska, gdzie czytelność dla człowieka liczy się bardziej niż przetwarzanie maszynowe.

Czy VS Code natywnie obsługuje JSON5?

Nie w standardowej instalacji. Wbudowane rozszerzenie JSON w VS Code rejestruje m.in. języki json, jsonc i jsonl, ale nie json5, więc pliki .json5 potrzebują rozszerzenia z marketplace, żeby mieć podświetlanie składni. JSONC jest wbudowany: ustawienia, tasks.json, launch.json i tsconfig.json otwierają się w trybie JSON with Comments.

Jak skonwertować JSON5 do standardowego JSON?

Wystarczy użyć pakietu npm json5: JSON5.parse() wczytuje JSON5, a następnie JSON.stringify() zwraca standardowy JSON. W wersji CLI można uruchomić npx json5 < input.json5 > output.json. Komentarze przy tym przepadają, a Infinity i NaN w JSON.stringify zamieniają się w null. Narzędzia online, takie jak nasz JSON Formatter, potrafią również zwalidować skonwertowany wynik, aby potwierdzić jego poprawność.

Czy JSONC to to samo co JSON with Comments?

Tak. „JSON with Comments” to nazwa trybu językowego w VS Code, a jsonc to jego identyfikator języka i rozszerzenie pliku. Format nie ma formalnego standardu; na jsonc.org dostępny jest społecznościowy szkic oparty na tym, co jsonc-parser akceptuje w ustawieniach domyślnych. Do standardowego JSON dochodzą komentarze // i /* */, a obsługa przecinków kończących zależy od parsera.

Aby poznać więcej narzędzi deweloperskich działających w przeglądarce — w tym kodowanie Base64, generowanie sum kontrolnych i konwersję timestampów — warto zajrzeć do naszego przewodnika po niezbędnych narzędziach dla programistów.

Podsumowanie

Zachowanie równowagi między czytelnością a rygorem to klasyczne wyzwanie deweloperskie. JSON5 oraz JSONC poprawiają komfort pisania, a w połączeniu z odpowiednim pipeline’em buildowania i walidacji można bezpiecznie cieszyć się zaletami „pobłażliwego JSON”.

Źródła

Tagi: json json5 jsonc formatting developer-tools

Powiązane artykuły

Zobacz wszystkie artykuły