엄격한 JSON이 쉼표 하나 때문에 한밤중에 디버깅을 하게 만든다면, 조금 더 관대한 JSON5와 JSON with Comments (JSONC)가 답일 수 있습니다.
JSON5란 무엇인가요?
JSON5(ES5 호환 JSON 확장)는 ECMAScript 5.1의 기능을 가져온 JSON 확장입니다. 따옴표 없는 키, 후행 쉼표, 작은따옴표 문자열, 주석, 16진수 숫자를 지원합니다. 커뮤니티가 관리하며, 손으로 쓰는 설정 파일을 엄격한 JSON보다 읽기 쉽게 만드는 것이 목적입니다.
JSONC란 무엇인가요?
JSONC(주석이 포함된 JSON)는 표준 JSON에 한 줄 주석(//)과 블록 주석(/* */)을 추가한 최소 확장입니다. 후행 쉼표를 허용하는지는 파서에 따라 다릅니다. VS Code 설정과 tsconfig.json을 비롯한 TypeScript 설정 파일의 기본 형식입니다.
“관대한” JSON이 필요한 이유
- 가독성: 표준 JSON은 주석, 후행 쉼표, 작은따옴표를 금지하므로 설정 파일이나 예제에서 의도를 담기 어렵습니다.
- 팀 협업: 주석이 전혀 없는 거대한 JSON은 유지보수가 어렵고, 작은 수정 하나로 파일이 망가질 수 있습니다.
- DevOps: Kubernetes와 CI/CD 파이프라인은 JSON을 실시간으로 병합·생성합니다. 관대한 문법은 수동 수정 작업을 줄여 줍니다.
JSON5와 JSONC 한눈에 비교
| 기능 | JSON(RFC 8259) | JSONC | JSON5 |
|---|---|---|---|
// 및 /* */ 주석 | 불가 | 지원 | 지원 |
| 후행 쉼표 | 불가 | 파서에 따라 다름(아래 참고) | 지원(객체·배열마다 하나) |
| 따옴표 없는 키 | 불가 | 불가 | 지원 |
| 작은따옴표 문자열 | 불가 | 불가 | 지원 |
| 여러 줄에 걸친 문자열(줄바꿈 이스케이프) | 불가 | 불가 | 지원 |
16진수 숫자(0x1F) | 불가 | 불가 | 지원 |
.5, 5., 앞에 붙는 + | 불가 | 불가 | 지원 |
Infinity, NaN | 불가 | 불가 | 지원 |
2진수 숫자(0b101) | 불가 | 불가 | 불가 |
| 명세 | RFC 8259 / ECMA-404 | 정식 표준 없음. 사실상 VS Code와 jsonc-parser가 정의 | JSON5 명세 1.0.0 |
내장 JSON.parse / json.loads로 읽기 | 가능 | 불가 | 불가 |
출처: JSON5 명세, VS Code JSON 문서, RFC 8259. 2진수 행은 직접 확인했습니다. json5 2.2.3으로 JSON5.parse('{a: 0b101}')를 실행하면 JSON5: invalid character 'b' at 1:6 오류가 납니다.
한 줄 요약: JSON5는 자바스크립트(JavaScript) 객체 리터럴에 가깝고, JSONC는 주석을 허용할 뿐인 표준 JSON이라서 키와 문자열은 여전히 큰따옴표로 감싸야 합니다.
JSONC의 후행 쉼표는 파서에 따라 다릅니다
JSONC에는 공식 명세가 없습니다. Microsoft가 VS Code 설정 파일용으로 비공식적으로 도입했고, 파서인 jsonc-parser도 함께 공개했습니다. 커뮤니티 초안인 jsonc.org가 이를 정식화하려 하고 있지만, 후행 쉼표에 대해서는 파서가 “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 예제로 실행 |
Deno(deno.jsonc) | 허용 | Deno 설정 문서 |
어떤 JSONC 도구로 읽어도 통과하는 파일이 필요하다면 후행 쉼표는 빼세요.
문법 예제
일반 JSON(엄격)
{
"name": "Go Tools",
"features": ["Base64", "JSON Formatter"]
}
JSON5 예제
예제 파일: config.json5
// 개발 환경 설정
{
name: 'go-tools',
port: 0x1F90, // 16진수로 쓴 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 파일)이라고 부름 | 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.”(JavaScript 객체 리터럴이 아니라 실제 JSON이어야 함) | npm 문서, 직접 실행 |
Babel은 babel.config.json5라는 파일을 찾지 않습니다. .json5는 Babel 문서에 나온 확장자 목록에 없고, Babel이 JSON5로 읽는 것은 .json 쪽 파일입니다.
실제로 출력되는 오류 메시지
작은 파일 두 개를 런타임마다 넣어 보았습니다. comment.json에는 주석이 있습니다.
{
// 개발 서버 포트
"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: package.json에 // comment 한 줄을 넣은 경우
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 파싱 오류와 CSV 깨짐 해결을 참고하세요.
JSONC와 JSON5를 표준 JSON으로 변환하기
변환하면 주석은 모두 사라집니다. JSON에는 주석을 담을 자리가 없기 때문입니다. 주석이 달린 파일을 원본으로 두고, .json 출력은 생성된 산출물로 취급하세요.
Node.js: json5로 JSON5를 JSON으로 변환
// 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-parser로 JSONC를 JSON으로 변환
jsonc-parser는 Microsoft가 공개한 JSON with Comments용 파서입니다. 이 파서의 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이 출력되고 종료 코드 0으로 끝납니다. allowTrailingComma: true를 빼면 같은 파일에서 각 후행 쉼표 바로 뒤에 오는 } 위치에 PropertyNameExpected와 ValueExpected가 보고됩니다.
Python: json5 패키지
표준 라이브러리 json 모듈에는 주석을 허용하는 옵션이 없습니다. json5 패키지는 JSON5를 읽으며, 주석과 후행 쉼표는 둘 다 JSON5에서 유효한 문법이므로 JSONC도 읽을 수 있습니다.
# 설치: 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으로 테스트한 결과, Node 버전과 같은 JSON이 출력됩니다.
명령줄: json5 CLI
json5 npm 패키지에는 JSON으로 변환하고 유효성 검사도 하는 CLI가 들어 있습니다. JSONC 파일도 읽을 수 있습니다.
npx json5 config.json5 # 공백 없는 JSON을 표준 출력으로
npx json5 -s 2 -o config.json config.json5 # 들여쓰기해서 파일로 저장
npx json5 -v tsconfig.json # 유효성 검사만 수행, 구문 오류 시 종료 코드 1
-v는 구문 오류가 있으면 종료 코드 1로 끝나므로, 같은 명령을 손으로 편집한 JSON5나 JSONC 파일을 검사하는 CI 단계로 그대로 쓸 수 있습니다.
여기서는 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 포맷터에 붙여넣어 유효성 검사와 정렬을 하세요. 브라우저 안에서 실행됩니다.
단, 이 포맷터는 엄격한 JSON만 받습니다. 브라우저의 JSON.parse로 파싱하므로 JSONC나 JSON5 파일을 그대로 붙여넣으면 구문 오류와 함께 파싱이 멈춘 행과 열이 표시됩니다. 먼저 변환하고 나서 유효성 검사를 하세요.
JSONC나 JSON5를 쓰지 말아야 할 때
- API 페이로드와 데이터 교환. RFC 8259는 JSON 생성기가 “MUST strictly conform to the JSON grammar”(JSON 문법을 엄격히 따라야 한다)라고 규정합니다. 받는 쪽은 대개
JSON.parse나json.loads이고, 둘 다 주석을 거부합니다. package.json. npm은 엄격한 JSON을 요구합니다. 주석이 하나만 있어도npm run같은 npm 명령이EJSONPARSE로 실패합니다.- 직접 관리하지 않는 도구가 읽는 파일. Node의
require('./tsconfig.json')은 엄격한 JSON 파서를 쓰므로 주석이 있는 tsconfig에서 실패합니다(SyntaxError: …tsconfig.json: Expected property name or '}' in JSON at position 4). JSONC 파일을 읽는 스크립트라면 JSONC 파서가 필요합니다. - 어느새 JSONC가 되어 버린
.json파일. Renovate 문서는 주석이 달린.json파일이 “can cause issues with editors and syntax highlighting”(에디터와 구문 강조에서 문제를 일으킬 수 있다)라며, 그보다.jsonc파일을 권장합니다. 확장자를 명시해 두면 어떤 도구든 무엇을 예상해야 하는지 알 수 있습니다.
설정 형식을 처음부터 고르는 중이고 어디서나 주석을 쓰고 싶다면, TOML과 YAML은 주석을 기본으로 지원합니다. TOML vs JSON vs YAML: 어떤 설정 형식을 써야 할까?를 참고하세요.
실전 설정 파일
JSON5와 JSONC는 이미 일상의 설정 파일에서 폭넓게 쓰입니다. 구체적인 예를 봅니다.
TypeScript (tsconfig.json — JSONC)
{
// 엄격 모드는 컴파일 시점에 더 많은 버그를 잡아 줍니다
"compilerOptions": {
"strict": true,
"target": "ES2022",
"module": "ESNext",
"outDir": "./dist",
// import 경로를 깔끔하게 만드는 경로 별칭
"paths": {
"@/*": ["./src/*"],
"@tests/*": ["./tests/*"],
},
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"],
}
TypeScript의 tsconfig.json은 JSONC를 기본으로 씁니다. 별도 설정 없이 주석과 후행 쉼표를 쓸 수 있습니다. JavaScript/TypeScript 프로젝트에서 가장 흔히 보는 JSONC 파일입니다.
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.parse는 엄격한 JSON만 받습니다. 앞의 변환 섹션에서 소개한 방법으로 빌드 단계에서 변환해 두세요.
2. 보안과 신뢰성
관대한 문법은 의도치 않은 필드를 숨길 수 있습니다. 설정을 쓰기 전에 JSON Schema나 zod로 유효성 검사를 하세요.
// 파싱 후 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 규칙을 표준화해 불필요한 diff 잡음을 줄입니다.
.editorconfig로 JSON, JSON5, JSONC 파일 전반의 들여쓰기를 일관되게 유지합니다.
4. 성능
JSON5/JSONC 파싱은 의존성과 약간의 오버헤드를 더합니다. CLI나 개발 도구에는 문제가 없지만, 운영 환경에서는 실제로 측정해 보세요. 시작 시 한 번 로드하는 설정 파일에는 무시할 수준입니다. 초당 수천 개의 객체를 파싱하는 핫 패스라면 엄격한 JSON을 쓰세요.
자주 묻는 질문
JSON5와 JSONC의 차이는 무엇인가요?
JSONC는 표준 JSON에 한 줄 주석(//)과 블록 주석(/* */)을 추가한 형식이며, 후행 쉼표 허용 여부는 파서에 따라 다릅니다. JSON5는 ES5.1 문법을 가져와 더 넓게 확장합니다. 따옴표 없는 키, 작은따옴표, 16진수, 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를 기본으로 지원하나요?
기본 설치 상태로는 지원하지 않습니다. VS Code에 내장된 JSON 확장은 json, jsonc, jsonl 등의 언어를 등록하지만 json5는 등록하지 않으므로, .json5 파일에 구문 강조를 적용하려면 마켓플레이스 확장이 필요합니다. JSONC는 기본으로 지원합니다. 설정 파일, tasks.json, launch.json, tsconfig.json은 모두 JSON with Comments 모드로 열립니다.
JSON5를 표준 JSON으로 어떻게 변환하나요?
json5 npm 패키지를 씁니다. JSON5.parse()로 JSON5를 읽은 뒤 JSON.stringify()로 표준 JSON을 출력합니다. CLI에서는 npx json5 < input.json5 > output.json. 변환하면 주석은 사라지고, Infinity와 NaN은 JSON.stringify를 거치면서 null이 됩니다. JSON 포맷터 같은 온라인 도구로 변환 결과를 검증할 수 있습니다.
JSONC는 JSON with Comments와 같은 것인가요?
네. “JSON with Comments”는 VS Code의 언어 모드 이름이고, jsonc는 그 언어 ID이자 파일 확장자입니다. VS Code, TypeScript(tsconfig.json), 그 외 Microsoft 도구에서 씁니다. 정식 표준은 없으며, jsonc.org에 jsonc-parser가 기본 옵션으로 허용하는 문법을 바탕으로 한 커뮤니티 초안이 있습니다. 표준 JSON 문법에 //와 /* */ 주석을 더한 형식이고, 후행 쉼표 허용 여부는 파서에 따라 다릅니다. 파서가 처리 전에 주석을 제거하므로 결과 데이터 구조는 표준 JSON과 동일합니다.
Base64 인코딩, 해시 생성, 타임스탬프 변환은 개발자 필수 도구 가이드에서 함께 다룹니다.
마무리
JSON5와 JSONC는 작성 경험을 편하게 해 줍니다. 빌드에서 엄격한 JSON으로 변환하고 zod 같은 스키마로 검증만 해 두면 안전하게 쓸 수 있습니다.