본문으로 건너뛰기
yutils

설정 파일은 어떤 형식이 좋을까? (YAML · JSON · TOML · XML)

5 가지 설정 파일 포맷을 정면 비교 — YAML 의 7 가지 boolean, TOML 의 타입 있는 datetime, JSON 의 주석 부재, XML 의 namespace, INI 의 무규격. 상황에 맞는 포맷 고르기.

약 9분 읽기

Kubernetes 는 YAML, Cargo (Rust) 는 TOML, package.json 은 JSON, legacy 데스크탑 앱은 INI, Maven 은 XML. 같은 "설정" 인데 왜 이렇게 다양할까? 각 포맷의 강점·약점·함정·언제 무엇을 고르는지 정리한다.

5 가지 포맷 — 첫 인상

JSON

{
  "name": "yutils",
  "version": "0.1.0",
  "tools": 66
}

YAML

name: yutils
version: 0.1.0
tools: 66

TOML

name = "yutils"
version = "0.1.0"
tools = 66

XML

<project>
  <name>yutils</name>
  <version>0.1.0</version>
  <tools>66</tools>
</project>

INI

[project]
name = yutils
version = 0.1.0
tools = 66

JSON — 기계 친화, 사람 적당

장점:

  • RFC 8259 표준 (2017), 모든 언어 기본 지원
  • JavaScript 와 직접 호환 (이름의 J)
  • 구조 명확 — object / array / string / number / boolean / null
  • 파서 단순 (100 라인 안)

단점:

  • 주석 X — Crockford 의 의도 "config 가 아닌 data 교환용" 명시. 그러나 실제로는 config 로 자주 사용 → 주석 못 다는 불편
  • trailing comma 금지 — diff 가 깨짐
  • 중복 키 정의 X (파서마다 동작 다름)
  • IEEE 754 한계 — 큰 정수 정밀도 손실 (how-json-parsing-works 가이드 참조)

파생 — JSON5 / JSONC:

  • JSON5 (Mike Bostock) — 주석 + trailing comma + hex 숫자 허용
  • JSONC (Microsoft) — 주석 + trailing comma만 (tsconfig.json)

용도 — API 응답 (네트워크 직렬화), npm package.json, JSON Schema

YAML — 사람 친화, 함정 다수

장점:

  • 들여쓰기로 구조 표현 → 시각적 가독성 ↑
  • 주석 (#) 지원
  • JSON 의 superset — JSON 도 valid YAML
  • 다중 문서 (---) — Kubernetes 의 multi-resource 사용
  • anchor + alias (DRY)

유명한 함정 — Norway 버그

countries:
  - GB
  - NO   ← Norway? 아니다, NO 는 false!
  - SE

# YAML 1.1: NO 가 boolean false 로 파싱

YAML 1.1 의 7 가지 boolean 표기:

true:  yes, Yes, YES, true, True, TRUE, on, On, ON
false: no, No, NO, false, False, FALSE, off, Off, OFF

Norway, Sweden 의 ISO 코드 NO/SE 가 boolean 으로 잘못 해석. 명시적 quote 필요 ("NO"). YAML 1.2 (2009) 에서 true/false 만 boolean 으로 줄였지만 많은 파서가 여전히 1.1 모드.

더 함정

# 16 진수 같은 8-digit string 이 number 로 해석
version: 1.10   ← float 1.1 ("0" 손실)
mac: 00:01:02   ← sexagesimal (base-60) 으로 해석

# 들여쓰기 mix
items:
  - one
   - two   ← 3 space, 다른 list 로 인식

# null 의 함정
key:        ← value 가 null (의도: 빈 string?)
key: ""     ← 명시 빈 string

YAML 의 "사람 친화" 가 묘하게 "사람을 함정에 빠뜨림". Kubernetes / Docker / Ansible 사용자라면 익숙.

용도 — Kubernetes manifest, GitHub Actions, Ansible playbook, Docker Compose

디버깅 — YAML ↔ JSON 변환 로 JSON 변환 해 확인. boolean / number 으로 잘못 파싱된 값이 즉시 보임.

TOML — Tom 의 양심적 설정

Tom Preston-Werner (GitHub 공동창업자) 가 2013 년 발표. "YAML 의 함정 없이 INI 보다 강한 타입 시스템".

title = "My Project"

[database]
server = "192.168.1.1"
ports = [8001, 8001, 8002]
connection_max = 5000
enabled = true

[servers]
  [servers.alpha]
  ip = "10.0.0.1"
  dc = "eqdc10"

  [servers.beta]
  ip = "10.0.0.2"
  dc = "eqdc10"

장점:

  • 명시적 타입 — string은 "" 강제, boolean 만 true/false, datetime 은 RFC 3339
  • 주석 (#) 지원
  • 섹션 ([section]) — INI 호환 느낌
  • nested table ([a.b.c]) — 깊은 구조 가능
  • YAML 의 함정 0

단점:

  • 깊은 중첩이 길어짐 (XML 만큼)
  • JSON / YAML 만큼 ubiquitous X

용도 — Cargo (Rust), Poetry (Python), Hugo, Caddy. TOML ↔ JSON 로 JSON 변환 가능.

XML — 강력하지만 verbose

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.example</groupId>
  <artifactId>my-app</artifactId>
  <version>1.0.0</version>
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.13</version>
      <scope>test</scope>
    </dependency>
  </dependencies>
</project>

장점:

  • XML Schema (XSD) 으로 strict validation
  • namespace — 다른 schema 의 element 혼합 가능
  • attribute vs element 구분 (메타데이터 vs 콘텐츠)
  • XSLT / XPath 같은 강력한 변환·query 언어
  • self-describing — 태그가 의미 표현

단점:

  • 매우 verbose — 같은 데이터에 JSON 의 3-5 배 크기
  • attribute vs child 선택의 모호함 (<port>8080</port> vs <server port="8080"/>?)
  • XXE attack (XML External Entity) — 외부 entity 참조로 파일 시스템 노출 가능
  • 주석은 있지만 attribute 안엔 못 박음

XXE 예시:

<!DOCTYPE foo [<!ENTITY xxe SYSTEM "file:///etc/passwd">]>
<root>&xxe;</root>
<!-- 파서가 entity expand → /etc/passwd 노출 -->

파서마다 external entity 기본 disable 여부 다름. Spring / Jackson XML 의 옛 버전이 자주 취약했음.

용도 — Maven (pom.xml), Android resource, RSS / Atom feed, SOAP, SVG, MS Office (docx 의 내부도 XML). XML 포매터 / XML ↔ JSON.

INI — 90 년대 표준, 비표준

[Database]
Server=192.168.1.1
Port=5432
Enabled=true

# 주석 (또는 ; 사용)
[Logging]
Level=info
File=/var/log/app.log

장점:

  • 단순 — 30 분 안에 파서 만들 수 있음
  • 섹션으로 그룹화
  • Windows 의 INI 파일 / .gitconfig / php.ini / systemd unit

단점:

  • 표준 없음 — 파서마다 quote 처리, escape, nested section 동작 다름
  • nested 구조 X (또는 . 또는 : 으로 편법)
  • array 표현 X
  • type 인식 X — 모두 string, 사용자가 변환

용도 — legacy Windows config, .gitconfig, php.ini, systemd unit files, MySQL my.cnf. INI ↔ JSON.

매트릭스 비교

JSONYAMLTOMLXMLINI
주석✅ (#)✅ (#)✅ (<!---->)
중첩✅ 무제한✅ 무제한✅ 무제한✅ 무제한1 단계 (편법으로 더)
배열반복 element
타입5 종유동적 (함정)명시 7 종 + datetime모두 string + XSD모두 string
표준RFC 8259YAML 1.2TOML 1.0W3C XML 1.0비표준
크기 (같은 데이터)1.0×0.7×0.8×3.0×0.6×
schemaJSON SchemaJSON Schema 호환XXSD / Relax NGX
다중 문서X✅ (---)XXX

언제 어떤 포맷

  • API 응답 / 네트워크 직렬화 — JSON. 모든 언어 기본 지원, 작은 크기.
  • Kubernetes / GitHub Actions / Ansible — YAML. ecosystem 표준. 함정 조심.
  • Rust Cargo / Python Poetry / Hugo — TOML. 개발자 도구의 깔끔한 default.
  • Maven / Android resource / RSS / SOAP — XML. legacy + schema validation 강한 곳.
  • Windows config / systemd / .gitconfig — INI. 단순.
  • 새 프로젝트 default:
    • 구조 깊고 사용자 편집 자주 — TOML
    • YAML 생태계 (k8s/ansible) — YAML
    • API/저장 — JSON
  • 주석이 절대 필요한 config — JSON 피하고 YAML 또는 TOML

흔한 함정

1. YAML 의 들여쓰기 mix

tab vs space 혼용 — 일부 파서가 silently 다른 트리 만듦. tab 금지가 spec.

2. JSON 주석 박기

// 이거 안 됨
{
  "name": "x",
  // 설명
  "value": 1
}

tsconfig.json 의 주석은 VS Code 의 JSONC 모드. 표준 JSON 파서는 에러.

3. TOML 의 datetime 타입 오해

# Offset datetime (UTC 정보 있음)
date1 = 1979-05-27T07:32:00Z

# Local datetime (offset 없음)
date2 = 1979-05-27T07:32:00

# Local date
date3 = 1979-05-27

TOML 의 datetime 4 type 이 명시. JSON 으로 변환하면 string 으로 flat 됨 — 정보 손실 가능.

4. XML 의 entity 폭탄

<!DOCTYPE lolz [
  <!ENTITY lol "lol">
  <!ENTITY lol2 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
  <!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;">
]>
<root>&lol3;</root>
<!-- 1억 글자로 expand → DoS -->

"billion laughs" attack. 모던 파서 default 로 entity 제한.

5. INI 의 escape 가정

파서 A: key=value with = sign → value = "value with = sign". 파서 B: 첫 = 만 인식 → 같은 결과. 파서 C: escape 없으면 에러. quote 필요한가? 표준 없으므로 라이브러리별 다름.

참고 자료

요약

  • JSON = data 교환 표준. 주석 / trailing comma X. 가장 ubiquitous.
  • YAML = 사람 친화 + 함정 다수 (Norway 버그, 들여쓰기, type coerce). k8s/CI 표준.
  • TOML = YAML 의 함정 없이 명시적 타입. Rust/Python 도구 default.
  • XML = verbose + 강한 schema (XSD). XXE attack 주의.
  • INI = 단순 + 비표준. legacy 시스템.
  • 포맷 선택 = ecosystem (어떤 도구가 read?) + 사용자 (사람 vs 기계) + 복잡도 (nested vs flat).
  • 변환 — YAML ↔ JSON 변환 / TOML ↔ JSON / XML ↔ JSON 로 JSON 으로 통일해 디버깅. INI ↔ JSON / XML 포매터 / JSON 포매터 / 검증기.
가이드 목록으로