JSON, TOML, YAML, CSON: 설정 형식 선택 가이드
핵심 요약: 설정 파일에는 주석, 날짜, 여러 줄 텍스트가 필요하며, 여기서 JSON이 부족합니다. JSON, TOML, YAML, CSON을 비교하고 변환에서 항상 잃는 것이 무엇인지 살펴봅니다.

핵심부터 말하면, 기계 간 교환에는 JSON을 쓰고, 사람이 관리하는 설정에는 생태계에 따라 TOML이나 YAML을 고르세요(Kubernetes와 CI에는 YAML, 평평한 구조나 네이티브 날짜에는 TOML). 판독기가 방언을 지원하는지 확실하지 않을 때만 JSONC로 대체하세요.
JSON은 기계가 데이터를 교환하기 위해 존재하고, 설정 파일은 사람이 사람을 위해 씁니다. 둘을 혼동하면 주석도 담을 수 없고 누구도 손대지 않는
config.json이 만들어집니다.
1. 먼저 두 종류의 파일을 구분하기
데이터 교환과 설정은 같은 목표를 공유하지 않습니다. 같은 사람이 같은 머신에서 둘 다 작성하는 경우가 많지만 말입니다.
| 차원 | 데이터 교환 | 설정 |
|---|---|---|
| 작성자 | 값을 직렬화하는 프로그램 | 사람, 또는 생성된 출력을 수정하는 사람 |
| 판독자 | 다른 사람의 프로그램 | 자신의 프로그램 |
| 중요한 것 | 모호함 제로, 크기, 파싱 속도 | 가독성, 주석, 리뷰 가능한 diff |
| 변경 빈도 | 매 요청 | 드물게, 리뷰와 함께 |
| 실수 비용 | 500 응답 | 서비스가 시작되지 않음 |
JSON은 왼쪽 열에서 거의 완벽합니다. 문법이 최소이고, 모든 언어에 파서가 있으며, 주석이 없다는 것은 "주석이 값에서 멀어지는" 문제가 없다는 뜻입니다. 오른쪽 열에서 엄격함은 순수한 마찰입니다. 주석 없음, 후행 쉼표 없음, 날짜 없음, 여러 줄 텍스트는 \n으로 한 줄에 접어야 합니다.
2. 네 후보와 문법
- JSON: RFC 8259와 ECMA-404로 정의되며, 값 타입은 정확히 여섯 가지입니다. 객체, 배열, 문자열, 숫자, 불리언,
null. 사실상의 교환 표준이며, 선택 판단이 필요 없는 유일한 형식입니다. - TOML: Tom Preston-Werner가 만들었고, v1.0.0은 2021년 1월에 발표되었습니다. 해시 테이블에 명확히 대응되는, 의미가 분명한 최소 설정 형식을 목표로 합니다.
Cargo.toml과pyproject.toml이 기본으로 사용합니다. - YAML: 현재 명세는 1.2.2입니다. 들여쓰기로 계층을 표현하고, 주석, 앵커, 여러 문서를 지원합니다. Kubernetes 매니페스트, GitHub Actions, Ansible이 모두 여기에 의존하며, 그 대가로 명세가 크고 구현 차이가 큽니다.
- CSON: CoffeeScript Object Notation으로, CoffeeScript 객체 리터럴로 설정을 씁니다. Atom의
config.cson이 사용했습니다. 주석, 따옴표 없는 키, 후행 쉼표를 지원하지만 생태계가 JavaScript 세계를 벗어나지 못했습니다.
2.1 기능 비교
| 기능 | JSON | TOML | YAML | CSON |
|---|---|---|---|---|
| 주석 | ✗ | ✓ # |
✓ # |
✓ # |
| 후행 쉼표 | ✗ | ✓ (배열, 인라인 테이블) | ✓ (플로 컬렉션) | ✓ |
| 따옴표 없는 키 | ✗ | ✓ | ✓ | ✓ |
| 네이티브 날짜/시간 | ✗ (문자열만) | ✓ 네 가지 날짜/시간 타입 | ✓ (1.1에서는 자동 파싱) | ✗ |
| 여러 줄 문자열 | ✗ (\n 이스케이프) |
✓ """와 ''' |
✓ 블록 및 폴디드 스칼라 | ✓ 히어도크 |
| 정수 범위 | 명세상 무한, 실제로는 더블 | 부호 있는 64비트, 손실 없어야 함 | 임의 정밀도 및 .inf/.nan |
JavaScript를 따름 |
| 중첩 | 중괄호와 대괄호 | 테이블, 테이블 배열, 점 표기 키 | 들여쓰기 | 들여쓰기 |
| 들여쓰기 민감 | ✗ | ✗ | ✓ | ✓ |
null |
✓ | ✗ | ✓ | ✓ |
| 도구 적용 범위 | 모든 언어 | 주류 언어 | 모든 언어, 구현 편차 | JavaScript만 |
두 셀에는 주석이 필요합니다. TOML에는 null이 없는데, 이것이 JSON에서 변환할 때 가장 흔한 실패입니다. YAML의 "네이티브 날짜" 동작은 1.1 파서가 2026-10-31을 자동으로 날짜 객체로 바꾼다는 뜻이라, 타입이 언어마다 달라집니다.
3. 주석: JSON의 유일한 약점
결론부터 말하면, 사람이 파일을 관리하고 값이 왜 그런지 설명해야 한다면 표준 JSON을 쓰지 마세요.
실용적인 네 가지 길이 있으며, 침습성이 적은 순서대로 나열합니다:
- JSONC로 전환. 표준 JSON에 주석과 후행 쉼표를 더한 것입니다. VS Code의
settings.json과tsconfig.json이 사용합니다. 비용은 판독기가jsonc-parser같은 주석 인식 파서를 써야 한다는 것이며, 평범한JSON.parse는 실패합니다. 자세한 내용은 JSON5와 JSONC: 주석이 있는 JSON에 있습니다. - 사이드카 문서 유지.
config.json은 기계가 읽을 수 있는 형태로 남기고,config.md가 각 필드의 의미와 값의 이유를 설명합니다. 둘은 같은 디렉터리에 있고 같은 커밋에서 변경됩니다. - 스키마에 설명 넣기. JSON Schema의
description과$comment키워드로 필드를 문서화할 수 있지만, 스키마가 런타임 설정과 함께 배포되는 경우가 드물어 설정을 읽는 사람이 볼 수 없을 수 있습니다. - TOML 또는 YAML로 이동. 형식 자체가 모든 파서가 이해하는 주석을 제공하게 합니다.
{
// Fixed at 8080: the frontend build script reads this port for its proxy
"port": 8080,
// Disable watching to avoid exhausting inodes in CI
"watch": false
}
JSONC는 여전히 방언입니다. 확장자는 .json으로 남지만, 일부 도구만 이해합니다. 데이터가 팀을 떠나거나 서비스 경계를 넘을 때 JSONC와 표준 JSON의 경계를 문서화해야 합니다.
4. 날짜와 여러 줄 문자열: TOML의 영역
TOML은 날짜/시간을 일급 타입으로 승격하며, 네 가지 변형이 있습니다. 오프셋 날짜/시간, 로컬 날짜/시간, 로컬 날짜, 로컬 시간. 여러 줄 문자열은 줄 바꿈을 보존하는 전용 문법이 있습니다:
title = "json-toolkit"
created = 2026-10-31T09:00:00+08:00
description = """
A JSON toolkit for developers.
Every operation runs locally in the browser.
"""
같은 정보를 JSON으로 표현하면 날짜를 문자열로 강등하고 줄 바꿈을 이스케이프해야 합니다:
{
"title": "json-toolkit",
"created": "2026-10-31T09:00:00+08:00",
"description": "A JSON toolkit for developers.\nEvery operation runs locally in the browser."
}
JSON에서 "created"는 우연히 날짜처럼 보이는 문자열일 뿐이라, 타입 정보는 필드 계약에 살아야 합니다. 양쪽이 이 필드가 항상 RFC 3339라고 동의해야 합니다. TOML은 말로 합의할 필요 없이 파서에 실제 날짜 객체를 줍니다.
YAML도 여러 줄 텍스트를 담을 수 있지만, 두 블록 스타일은 서로 다른 의미입니다. |는 줄 바꿈을 보존하고, >는 공백으로 접습니다. 잘못 고르면 주소나 SQL 문이 한 줄로 접혀 버리는데, 리뷰에서 잡기 매우 어려운 오류입니다.
5. 숫자: 가장 간과되는 차이
JSON 명세는 숫자 정밀도에 상한을 두지 않지만, RFC 8259는 숫자를 IEEE 754 더블로 처리할 때 상호 운용성이 가장 안전하다고 경고합니다. JavaScript에서는 2^53 - 1을 넘는 정수가 조용히 정밀도를 잃습니다:
JSON.parse('{"id":9007199254740993}').id
// 9007199254740992: the last digit is gone
TOML은 부호 있는 64비트 정수를 손실 없이 처리하고, 조용히 자르지 않고 오류를 내야 합니다. 부동소수점은 binary64를 따르며 inf 또는 nan도 될 수 있습니다. YAML 1.1은 더 오래된 짐을 지고 있습니다. 1:30은 90으로 파싱되고(육십진법), 불리언은 yes, no, on, off를 받아들입니다. 그래서 국가 코드 NO가 false가 되는 유명한 "노르웨이 문제"가 있습니다.
돈에는 어떤 형식에서도 부동소수점에 의존하지 마세요. 정수 최소 단위, 문자열, 또는 데이터베이스 십진 타입을 쓰세요. 형식화와 정밀도는 JSON, YAML, XML 변환의 경계에서 더 자세히 다룹니다.
6. 테이블과 중첩: TOML의 경성 경계
TOML은 테이블과 테이블 배열로 중첩을 표현합니다:
[server]
port = 8080
[[routes]]
path = "/parse"
method = "POST"
[[routes]]
path = "/minify"
method = "POST"
변환 전에 반드시 알아야 할 두 가지 경성 경계가 있습니다:
- TOML 문서의 루트는 테이블이므로, 최상위가 배열인 JSON 문서(예:
[1, 2, 3])는 합법적인 TOML 표현이 없습니다.{"items": [...]}로 감싸야 합니다. - TOML에는
null이 없습니다. JSON의null필드는 버리거나 빈 문자열 또는 센티널 값으로 대체해야 하며, 의미는 소비자에게 넘어갑니다.
YAML은 반대입니다. 중첩 깊이에 제한이 없고, 앵커와 병합 키로 조각을 재사용할 수 있습니다:
defaults: &defaults
retries: 3
timeoutMs: 5000
server:
<<: *defaults
port: 8080
앵커는 YAML만의 기능이며 변환 시 반드시 손실됩니다. JSON에는 참조 문법이 없어서, 확장된 파일이 커지고 두 부분이 원래 같은 설정이었다는 기록이 사라집니다.
7. 시나리오별 선택
| 시나리오 | 권장 | 이유 |
|---|---|---|
| 공개 API, 메시지 큐, 캐시 | JSON | 최대 보편성, 협상 비용 제로 |
| 애플리케이션 설정, 평평하고 타입이 있는 구조 | TOML | 주석, 날짜, 손실 없는 정수, 안정적인 파서 동작 |
| Kubernetes, CI, Ansible | YAML | 생태계가 고정되어 형식을 바꾸면 도구도 바꿔야 함 |
VS Code, tsconfig.json |
JSONC | 네이티브 지원, 새 형식을 도입할 필요 없음 |
| 설정 조각 재사용 | YAML | 앵커와 병합 키가 유일한 즉석 옵션 |
| 생성 전용, 기계만 사용 | JSON(압축) | 주석이 필요 없고 크기와 파싱 비용이 최적 |
| 레거시 Atom 또는 CoffeeScript 프로젝트 | CSON, 하지만 이전 계획 수립 | 생태계가 주변부이며 이전 비용은 시간에 따라 커짐 |
경험 법칙 하나: 설정 형식은 개인 취향이 아니라 생태계가 고르게 하세요. Rust를 쓴다면 Cargo.toml, Kubernetes에 배포한다면 YAML, VS Code 확장을 만든다면 JSONC입니다. 생태계 제약이 없는 신규 프로젝트에서만 "어느 쪽이 더 쓰기 좋은가"가 진짜 질문이 됩니다.
8. 변환 경계
| 방향 | 항상 잃는 정보 | 조언 |
|---|---|---|
| JSON → TOML | null, 최상위 배열, 표현 불가능한 키 |
먼저 구조를 정규화하고 빈 필드를 버리세요 |
| TOML → JSON | 주석, 날짜 타입, inf / nan |
날짜를 RFC 3339 문자열로 변환하세요 |
| YAML → JSON | 주석, 앵커와 병합 키, 태그, 여러 문서 | 먼저 앵커를 확장한 뒤 문서 단위로 변환하세요 |
| JSON → YAML | 구조 손실은 없지만 날짜 문자열이 자동 파싱될 수 있음 | 날짜 문자열에 따옴표를 붙이세요 |
| CSON → JSON | 주석, CoffeeScript 표현식 | 한 번만 이전하고 양방향 동기화는 하지 마세요 |
변환 도구는 값을 보장하지 주석은 절대 보장하지 않습니다. 따라서 "JSON이 원본이고 YAML은 빌드 산출물"인 양방향 파이프라인을 설계하지 마세요. 한 방향으로만 생성하거나, 단일 원본 파일을 유지하세요.
9. 체크리스트
- [ ] 어떤 파일 타입이 어떤 형식을 쓰는지 문서화하고, 허용되는 방언을 나열합니다
- [ ] 사람이 관리하는 설정에는 TOML이나 YAML, 기계 교환에는 JSON을 우선합니다
- [ ] JSON의 날짜는 RFC 3339 문자열로 저장하고 스키마에 형식을 표시합니다
- [ ] 돈과
2^53을 넘는 정수는 문자열이나 최소 단위로 표현하고 부동소수점으로 쓰지 않습니다 - [ ] CI에서 각 형식을 자체 파서로 검증하고, YAML에는 절대
JSON.parse를 쓰지 않습니다 - [ ] 형식 이전은 한 방향으로만 하고, 이전 후 옛 파일을 삭제해 둘이 어긋날 수 없게 합니다
FAQ
JSON을 TOML로 변환할 때 일부 필드에서 실패하는 이유는?
TOML에는 null이 없고 TOML 문서의 루트는 테이블이므로, JSON의 null 필드는 버리거나 빈 문자열 또는 센티널로 대체해야 하고, 최상위 배열은 {"items": [...]}로 감싸야 합니다. 반대 방향에서는 주석, 날짜 타입, inf/nan도 손실되므로 변환은 단방향이어야 합니다.
서로 다른 형식의 설정 파일 두 개를 유지해야 하나?
아니요. 변환 도구는 값을 보장하지만 주석은 절대 보장하지 않으므로, "JSON이 원본이고 YAML은 빌드 산출물"인 파이프라인은 어긋납니다. 한 방향으로만 생성하거나, 단일 원본 파일을 유지하고 이전 후 옛 파일을 삭제하세요.
JSON 설정 파일에 주석을 어떻게 추가하나?
표준 JSON에는 주석이 없습니다. JSONC(VS Code 방언, jsonc-parser로 읽음)로 전환하거나, 각 필드를 설명하는 사이드카 문서를 유지하거나, TOML이나 YAML로 이동할 수 있습니다. 다른 시스템으로 보내는 파일은 표준 JSON으로 남기고 설명은 문서나 스키마에 두세요.
애플리케이션 설정에는 TOML과 YAML 중 어느 쪽이 나은가?
구조가 평평하고 주로 키-값 쌍이며 네이티브 날짜가 중요하다면 TOML을 고르세요. 의미가 더 예측 가능하고 파서 차이가 작습니다. 깊은 중첩, 여러 문서, 앵커 재사용이 필요하거나 Kubernetes나 CI처럼 대상 생태계가 YAML 우선이라면 YAML을 고르세요. 둘 다 주석을 지원하므로 진짜 차이는 구조 복잡성과 생태계 고정입니다.
YAML에서 NO가 false가 되는 이유는?
YAML 1.1은 yes, no, on, off, y, n을 불리언으로 취급하므로 노르웨이 국가 코드 NO가 false로 파싱됩니다. 이것이 "노르웨이 문제"입니다. YAML 1.2를 따르는 구현을 쓰거나, 오해될 수 있는 모든 문자열에 따옴표를 붙여 피하세요.
CSON은 아직 쓸 만한가?
신규 프로젝트에는 아닙니다. CSON은 CoffeeScript 생태계에 의존하고, 유지 관리되는 도구가 적으며, 에디터와 CI 지원이 제한적입니다. Atom이 유지 관리를 중단한 뒤 사용 사례는 더 줄었습니다. 이미 CSON 설정이 있는 프로젝트는 더 늘리지 말고 JSON, TOML, YAML로 일회성 이전을 계획하세요.