YAML에서 JSON으로의 변환은 개발자가 매일 직면하는 가장 일반적인 데이터 형식 작업 중 하나입니다. Kubernetes 매니페스트, Docker Compose 파일, CI/CD 파이프라인을 관리할 때 YAML과 JSON 간의 변환이 자주 필요합니다. 이 종합 가이드에서는 변환 도구, 파싱 프로세스, 코드 예제, 모범 사례를 다룹니다.
무료 온라인 YAML to JSON / JSON to YAML 변환 도구를 사용해 보세요.
YAML이란?
YAML(YAML Ain't Markup Language)은 구성 파일과 데이터 교환에 널리 사용되는 인간 친화적 데이터 직렬화 언어입니다. YAML 파서는 들여쓰기 기반 구조를 읽어 네이티브 데이터 구조로 변환합니다.
YAML은 공백 들여쓰기(탭 금지)로 구조를 나타냅니다. 스칼라 타입, 시퀀스(배열), 매핑(딕셔너리)을 지원하며, 앵커와 별칭, 여러 줄 문자열, ---로 구분된 다중 문서 등 고급 기능을 제공합니다. YAML 구문은 JSON의 상위 집합입니다.
YAML은 Kubernetes, Ansible, Docker Compose, GitHub Actions 등 많은 클라우드 네이티브 도구의 선호 형식입니다.
YAML vs JSON: 주요 차이점
차이점을 이해하면 올바른 형식을 선택하는 데 도움이 됩니다:
| 특징 | YAML | JSON |
|---|---|---|
| 구문 | 들여쓰기 기반 | 괄호/중괄호 구분 |
| 주석 | #으로 지원 | 미지원 |
| 데이터 타입 | 문자열, 정수, 실수, 불리언, null, 날짜 | 문자열, 숫자, 불리언, null, 배열, 객체 |
| 가독성 | 매우 읽기 쉬움 | 더 장황함 |
| 속도 | 느림 | 빠름 |
YAML에서 JSON 변환 작동 원리
YAML to JSON 변환기는 다단계 파싱 및 직렬화 프로세스를 수행합니다.
1단계: 어휘 분석 — YAML 파서가 토큰을 식별합니다.
2단계: AST 구축 — 토큰이 추상 구문 트리로 조립됩니다.
3단계: 네이티브 데이터 구조 — AST가 타입 해석과 함께 네이티브 구조로 변환됩니다.
4단계: JSON 직렬화 — 구조가 JSON으로 직렬화됩니다. YAML 주석은 제거됩니다.
YAML to JSON 코드 예제
JavaScript / Node.js (js-yaml)
js-yaml은 JavaScript용 가장 인기 있는 YAML 파서입니다:
// ===== YAML to JSON (Node.js) =====
const yaml = require('js-yaml');
const fs = require('fs');
// Parse YAML string to JavaScript object
const yamlString = `
server:
host: localhost
port: 8080
ssl: true
database:
name: myapp
replicas:
- host: db1.example.com
port: 5432
- host: db2.example.com
port: 5432
# Connection pool settings
pool:
min: 5
max: 20
`;
const data = yaml.load(yamlString);
const json = JSON.stringify(data, null, 2);
console.log(json);
// {
// "server": {
// "host": "localhost",
// "port": 8080,
// "ssl": true
// },
// "database": {
// "name": "myapp",
// "replicas": [
// { "host": "db1.example.com", "port": 5432 },
// { "host": "db2.example.com", "port": 5432 }
// ],
// "pool": { "min": 5, "max": 20 }
// }
// }
// ===== JSON to YAML =====
const jsonData = { name: 'app', version: '2.0', features: ['auth', 'logging'] };
const yamlOutput = yaml.dump(jsonData, { indent: 2 });
console.log(yamlOutput);
// name: app
// version: '2.0'
// features:
// - auth
// - logging
// ===== Read YAML file and convert to JSON =====
const fileContent = fs.readFileSync('config.yaml', 'utf8');
const config = yaml.load(fileContent);
fs.writeFileSync('config.json', JSON.stringify(config, null, 2));
// ===== Handle multi-document YAML =====
const multiDoc = `
---
name: doc1
---
name: doc2
`;
const docs = yaml.loadAll(multiDoc);
console.log(JSON.stringify(docs, null, 2));
// [{ "name": "doc1" }, { "name": "doc2" }]Python (PyYAML)
임의 코드 실행 방지를 위해 항상 yaml.safe_load()를 사용하세요:
import yaml
import json
# ===== YAML to JSON =====
yaml_string = """
server:
host: localhost
port: 8080
ssl: true
database:
name: myapp
replicas:
- host: db1.example.com
port: 5432
- host: db2.example.com
port: 5432
pool:
min: 5
max: 20
"""
# Always use safe_load (prevents arbitrary code execution)
data = yaml.safe_load(yaml_string)
json_output = json.dumps(data, indent=2, ensure_ascii=False)
print(json_output)
# ===== JSON to YAML =====
json_string = '{"name": "app", "version": "2.0", "features": ["auth", "logging"]}'
json_data = json.loads(json_string)
yaml_output = yaml.dump(json_data, default_flow_style=False, allow_unicode=True)
print(yaml_output)
# ===== File conversion =====
# YAML file to JSON file
with open('config.yaml', 'r') as yf:
config = yaml.safe_load(yf)
with open('config.json', 'w') as jf:
json.dump(config, jf, indent=2)
# JSON file to YAML file
with open('data.json', 'r') as jf:
data = json.load(jf)
with open('data.yaml', 'w') as yf:
yaml.dump(data, yf, default_flow_style=False)
# ===== Handle multi-document YAML =====
multi_yaml = """
---
name: doc1
type: config
---
name: doc2
type: data
"""
docs = list(yaml.safe_load_all(multi_yaml))
print(json.dumps(docs, indent=2))
# ===== Preserve key order (Python 3.7+) =====
# dict maintains insertion order by default
ordered = yaml.safe_load(yaml_string)
print(json.dumps(ordered, indent=2)) # keys stay in YAML orderBash / CLI (yq)
명령줄 변환에서 yq가 가장 효율적입니다:
# ===== yq: YAML processor (like jq for YAML) =====
# Convert YAML file to JSON
yq -o=json config.yaml
# Convert YAML to JSON and save to file
yq -o=json config.yaml > config.json
# Convert JSON to YAML
yq -P config.json
# Convert JSON to YAML and save
yq -P config.json > config.yaml
# Extract a specific field from YAML as JSON
yq -o=json '.server.port' config.yaml
# ===== Python one-liner =====
# YAML to JSON (stdin)
cat config.yaml | python3 -c \
'import sys,yaml,json; json.dump(yaml.safe_load(sys.stdin),sys.stdout,indent=2)'
# YAML to JSON (file)
python3 -c \
'import yaml,json; print(json.dumps(yaml.safe_load(open("config.yaml")),indent=2))'
# JSON to YAML
cat data.json | python3 -c \
'import sys,yaml,json; print(yaml.dump(json.load(sys.stdin),default_flow_style=False))'
# ===== Ruby one-liner =====
ruby -ryaml -rjson -e 'puts JSON.pretty_generate(YAML.load($stdin.read))' < config.yaml
# ===== Pipe YAML from curl to JSON =====
curl -s https://raw.githubusercontent.com/example/repo/main/config.yaml | \
yq -o=json
# ===== Validate YAML before converting =====
yamllint config.yaml && yq -o=json config.yamlGo (gopkg.in/yaml.v3)
Go에서 gopkg.in/yaml.v3는 강력한 YAML 파싱을 제공합니다:
package main
import (
"encoding/json"
"fmt"
"log"
"gopkg.in/yaml.v3"
)
func main() {
// YAML input string
yamlData := []byte(`
server:
host: localhost
port: 8080
ssl: true
database:
name: myapp
replicas:
- host: db1.example.com
port: 5432
- host: db2.example.com
port: 5432
`)
// Parse YAML into interface{}
var data interface{}
err := yaml.Unmarshal(yamlData, &data)
if err != nil {
log.Fatalf("YAML parse error: %v", err)
}
// Convert map[string]interface{} keys for JSON compatibility
data = convertMapKeys(data)
// Marshal to JSON
jsonData, err := json.MarshalIndent(data, "", " ")
if err != nil {
log.Fatalf("JSON marshal error: %v", err)
}
fmt.Println(string(jsonData))
}
// convertMapKeys recursively converts map[interface{}]interface{}
// to map[string]interface{} for JSON compatibility
func convertMapKeys(v interface{}) interface{} {
switch v := v.(type) {
case map[string]interface{}:
result := make(map[string]interface{})
for key, val := range v {
result[key] = convertMapKeys(val)
}
return result
case []interface{}:
for i, val := range v {
v[i] = convertMapKeys(val)
}
return v
default:
return v
}
}JSON에서 YAML로 변환
역방향 변환도 API JSON 데이터를 YAML 구성으로 저장할 때 중요합니다.
주석이 손실됩니다. 주석을 보존하려면 ruamel.yaml을 사용하세요.
모범 사례: 2칸 들여쓰기, 플로우 스타일 회피, 모호한 문자열 인용, 출력 검증.
일반적인 YAML 함정
YAML의 유연성은 여러 함정을 만듭니다:
탭 vs 스페이스 — YAML은 들여쓰기에 탭을 금지합니다.
불리언 함정 — yes, no, on, off는 불리언으로 해석됩니다.
# The YAML boolean trap - these all become true or false in JSON!
# YAML 1.1 boolean values (case-insensitive):
is_active: yes # → true
is_active: no # → false
is_active: on # → true
is_active: off # → false
is_active: y # → true
is_active: n # → false
is_active: true # → true
is_active: false # → false
# Real-world problems:
countries:
- US # string "US" ✓
- GB # string "GB" ✓
- NO # boolean false ✗ (Norway disappears!)
- FR # string "FR" ✓
# Fix: always quote ambiguous values
countries:
- "US"
- "GB"
- "NO" # string "NO" ✓
- "FR"
# Version numbers are also problematic:
version: 1.0 # → float 1 (not string "1.0")
version: "1.0" # → string "1.0" ✓여러 줄 문자열 — |는 줄바꿈 유지, >는 공백으로 대체합니다.
# YAML multiline string variants
# Literal block scalar (|) - preserves newlines
description: |
This is line one.
This is line two.
This is line three.
# JSON: "This is line one.\nThis is line two.\nThis is line three.\n"
# Folded block scalar (>) - replaces newlines with spaces
description: >
This is a long
paragraph that will
be folded into one line.
# JSON: "This is a long paragraph that will be folded into one line.\n"
# Chomping indicators:
keep_trailing: |+ # Keep ALL trailing newlines
text
strip_trailing: |- # Strip ALL trailing newlines
text
clip_trailing: | # Keep exactly ONE trailing newline (default)
text특수 문자 — 값의 콜론과 괄호는 인용이 필요합니다.
앵커와 별칭 — JSON 변환 시 완전히 확장됩니다.
# YAML anchors and aliases
# Define an anchor with &
defaults: &default_settings
adapter: postgres
host: localhost
port: 5432
# Reuse with alias *
development:
database:
<<: *default_settings # Merge key: inherits all defaults
database: myapp_dev
production:
database:
<<: *default_settings # Same defaults
database: myapp_prod
host: db.production.com # Override specific values
# After JSON conversion (anchors fully expanded):
# {
# "defaults": { "adapter": "postgres", "host": "localhost", "port": 5432 },
# "development": {
# "database": {
# "adapter": "postgres", "host": "localhost",
# "port": 5432, "database": "myapp_dev"
# }
# },
# "production": {
# "database": {
# "adapter": "postgres", "host": "db.production.com",
# "port": 5432, "database": "myapp_prod"
# }
# }
# }숫자와 날짜 해석 — 1.0은 문자열이 아닌 부동소수점이 됩니다.
YAML 모범 사례
깔끔하고 유지보수 가능한 YAML을 위한 모범 사례:
일관된 들여쓰기 — Kubernetes 규칙에 맞춰 2칸 스페이스.
방어적 문자열 인용 — 의심스러우면 따옴표 사용.
불리언 함정 회피 — 국가 코드와 토글 값에 주의.
스키마 검증 — JSON Schema로 검증.
yamllint 사용 — CI/CD 파이프라인에 통합.
# .yamllint.yml configuration example
---
extends: default
rules:
line-length:
max: 120
allow-non-breakable-words: true
indentation:
spaces: 2
indent-sequences: true
comments:
min-spaces-from-content: 1
truthy:
check-keys: true
allowed-values: ['true', 'false']
document-start:
present: true
trailing-spaces: enable
new-line-at-end-of-file: enable
# Run yamllint:
# yamllint .
# yamllint config.yaml
# yamllint -d "{extends: default}" config.yaml현명한 주석 사용 — JSON 변환 시 손실됨을 기억.
자주 묻는 질문
YAML과 JSON의 차이점은 무엇인가요?
YAML은 들여쓰기 기반이며 주석과 고급 기능을 지원합니다. JSON은 괄호 구분이며 주석 미지원, 제한된 타입을 가집니다. YAML은 구성 파일에, JSON은 API에 선호됩니다.
YAML을 JSON으로 변환하려면?
온라인 도구, CLI의 yq, 또는 라이브러리(JavaScript: js-yaml, Python: PyYAML, Go: gopkg.in/yaml.v3)를 사용합니다.
YAML과 JSON은 언제 사용하나요?
YAML은 사람이 자주 편집하는 구성 파일에. JSON은 API와 서비스 간 데이터 교환에 사용합니다.
YAML에서 JSON으로의 변환을 마스터하는 것은 현대 DevOps에 필수적입니다. 무료 도구와 YAML 검증기로 워크플로를 최적화하세요.