DevToolBox무료
블로그

JSON-YAML 변환 온라인 가이드: 구문, 도구, 모범 사례

14분 읽기by DevToolBox
TL;DR

JSON과 YAML은 현대 개발의 2대 데이터 직렬화 형식입니다. JSON은 API와 머신간 통신에, YAML은 사람이 편집하는 설정 파일에 적합합니다. YAML은 JSON의 상위 집합으로 주석, 앵커, 다중행 문자열을 지원합니다.

핵심 요점
  • JSON은 중괄호와 엄격한 인용을 사용; YAML은 들여쓰기와 최소한의 구두점 사용.
  • YAML은 주석(#), 앵커/별칭(&/*), 다중행 문자열(|과 >)을 지원.
  • "노르웨이 문제": 따옴표 없는 NO, YES, on, off가 YAML 1.1에서 불리언이 됨.
  • Python에서 yaml.load() 대신 항상 yaml.safe_load()를 사용.
  • Kubernetes, Docker Compose, GitHub Actions가 YAML을 주요 설정 형식으로 사용.
  • js-yaml(JavaScript), PyYAML(Python), yq(CLI)로 변환.

무료 JSON-YAML 변환 도구 사용해보기

JSON vs YAML: 구문 비교

JSON과 YAML은 같은 데이터를 다른 구문으로 표현합니다.

동일 데이터의 형식별 비교:

JSON 형식
{
  "server": {
    "host": "localhost",
    "port": 8080,
    "ssl": true
  },
  "database": {
    "name": "myapp",
    "replicas": [
      "db1.example.com",
      "db2.example.com"
    ]
  },
  "features": [
    "authentication",
    "logging",
    "rate-limiting"
  ]
}
YAML 형식
# Server configuration
server:
  host: localhost
  port: 8080
  ssl: true

# Database settings
database:
  name: myapp
  replicas:
    - db1.example.com
    - db2.example.com

features:
  - authentication
  - logging
  - rate-limiting

YAML은 중괄호, 대괄호, 따옴표를 제거하고 들여쓰기로 중첩을 표현합니다.

JSON과 YAML 사용 시기

선택은 파일을 읽고 쓰는 주체에 따라 달라집니다:

JSON 사용 시:
  • REST API 및 GraphQL 응답
  • 마이크로서비스 간 데이터 교환
  • MongoDB 데이터베이스
  • JavaScript/TypeScript 프로젝트
  • package.json 등 매니페스트
YAML 사용 시:
  • Kubernetes 매니페스트
  • Docker Compose 설정
  • CI/CD 파이프라인
  • Ansible 플레이북
  • 사람이 자주 편집하는 설정 파일

YAML 앵커, 별칭, 다중행 문자열

JSON에 없는 YAML의 강력한 기능들.

앵커와 별칭

앵커(&)로 재사용 블록 정의, 별칭(*)으로 참조:

# Define reusable defaults with an anchor
defaults: &default_db
  adapter: postgres
  host: localhost
  port: 5432
  pool_size: 10

# Reference with alias and override specific fields
development:
  database:
    <<: *default_db          # Merge all defaults
    database: myapp_dev
    pool_size: 5             # Override pool_size

staging:
  database:
    <<: *default_db
    database: myapp_staging
    host: staging-db.internal

production:
  database:
    <<: *default_db
    database: myapp_prod
    host: prod-db.internal
    pool_size: 25

# After JSON conversion (anchors fully expanded):
# {
#   "defaults": { "adapter": "postgres", "host": "localhost", "port": 5432, "pool_size": 10 },
#   "development": {
#     "database": { "adapter": "postgres", "host": "localhost", "port": 5432, "pool_size": 5, "database": "myapp_dev" }
#   },
#   ...
# }

다중행 문자열

YAML은 두 가지 블록 스칼라 스타일을 제공:

리터럴 블록(|): 줄바꿈 그대로 유지.

접힘 블록(>): 줄바꿈을 공백으로 대체.

# Literal block (|) - preserves newlines exactly
script: |
  #!/bin/bash
  echo "Starting deployment..."
  docker compose pull
  docker compose up -d
  echo "Done!"

# Folded block (>) - joins lines with spaces
description: >
  This is a long description
  that spans multiple lines.
  Each newline becomes a space
  in the resulting string.

# Strip trailing newline with |-
sql_query: |-
  SELECT users.name, orders.total
  FROM users
  JOIN orders ON users.id = orders.user_id
  WHERE orders.created_at > '2024-01-01'

# Keep all trailing newlines with |+
message: |+
  Line 1
  Line 2

  (trailing newlines preserved)


# JSON equivalents:
# "script": "#!/bin/bash\necho \"Starting...\n..."
# "description": "This is a long description that spans..."
# "sql_query": "SELECT users.name..."  (no trailing \n)

촘핑 지시자: |+ 모든 후행 줄바꿈 유지, |- 모두 제거.

JavaScript 변환(js-yaml)

js-yaml은 가장 널리 사용되는 JavaScript YAML 파서:

// npm install js-yaml
const yaml = require('js-yaml');
const fs = require('fs');

// ===== JSON to YAML =====
const jsonData = {
  apiVersion: 'apps/v1',
  kind: 'Deployment',
  metadata: { name: 'web-app', labels: { app: 'web' } },
  spec: {
    replicas: 3,
    selector: { matchLabels: { app: 'web' } },
    template: {
      spec: {
        containers: [{
          name: 'app',
          image: 'nginx:1.25',
          ports: [{ containerPort: 80 }]
        }]
      }
    }
  }
};

const yamlOutput = yaml.dump(jsonData, {
  indent: 2,
  lineWidth: 120,
  noRefs: true,       // Don't use YAML anchors
  sortKeys: false,     // Preserve key order
  quotingType: '"',    // Use double quotes
});
console.log(yamlOutput);

// ===== YAML to JSON =====
const yamlString = fs.readFileSync('config.yaml', 'utf8');
const parsed = yaml.load(yamlString);
const jsonString = JSON.stringify(parsed, null, 2);
fs.writeFileSync('config.json', jsonString);

// ===== Handle multi-document YAML =====
const multiDoc = `
---
name: service-a
port: 3000
---
name: service-b
port: 3001
`;
const docs = [];
yaml.loadAll(multiDoc, (doc) => docs.push(doc));
console.log(JSON.stringify(docs, null, 2));
// [{ "name": "service-a", "port": 3000 }, { "name": "service-b", "port": 3001 }]

TypeScript에서 내장 타입 정의 사용 가능.

무료 JSON-YAML 변환 도구 사용해보기

Python 변환(PyYAML, ruamel.yaml)

Python에는 두 가지 주요 YAML 라이브러리가 있습니다.

PyYAML

# pip install pyyaml
import yaml
import json

# ===== YAML to JSON =====
yaml_text = """
server:
  host: localhost
  port: 8080
  features:
    - auth
    - logging
  database:
    name: myapp
    ssl: true
"""

# ALWAYS use safe_load (never yaml.load with untrusted input)
data = yaml.safe_load(yaml_text)
json_output = json.dumps(data, indent=2, ensure_ascii=False)
print(json_output)

# ===== JSON to YAML =====
json_text = '{"name": "app", "version": "2.0", "debug": false}'
data = json.loads(json_text)
yaml_output = yaml.dump(data, default_flow_style=False, allow_unicode=True, sort_keys=False)
print(yaml_output)

# ===== File conversion =====
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, ensure_ascii=False)

# ===== Multi-document YAML =====
multi_yaml = """
---
name: doc1
value: 100
---
name: doc2
value: 200
"""
docs = list(yaml.safe_load_all(multi_yaml))
print(json.dumps(docs, indent=2))

ruamel.yaml(주석 보존)

ruamel.yaml은 주석을 보존하며 편집 가능:

# pip install ruamel.yaml
from ruamel.yaml import YAML
from io import StringIO
import json

yaml_handler = YAML()
yaml_handler.preserve_quotes = True

# Load YAML with comments preserved
yaml_text = """
# Application configuration
app:
  name: my-service    # Service name
  port: 3000          # Listen port
  debug: false
"""

data = yaml_handler.load(yaml_text)

# Modify a value
data['app']['port'] = 8080

# Write back - comments are preserved!
output = StringIO()
yaml_handler.dump(data, output)
print(output.getvalue())
# Output still has "# Application configuration" and inline comments

# Convert to JSON (comments lost in JSON, but preserved in YAML round-trip)
json_output = json.dumps(dict(data), indent=2, default=str)
print(json_output)

CLI 변환(yq, jq)

CLI 도구는 빠른 변환에 이상적:

yq: YAML 만능 도구

yq는 경량 YAML 처리기:

# Install yq (Mike Farah version)
# macOS: brew install yq
# Linux: snap install yq  OR  wget from GitHub releases
# Windows: choco install yq

# ===== YAML to JSON =====
yq -o=json config.yaml
yq -o=json '.' config.yaml > config.json

# ===== JSON to YAML =====
yq -o=yaml config.json
yq -o=yaml -P '.' config.json > config.yaml  # -P for pretty print

# ===== Query and filter =====
yq '.server.port' config.yaml              # Extract a value
yq '.spec.containers[0].image' deploy.yaml # Array access
yq '.metadata.labels' deploy.yaml          # Get nested object

# ===== Modify in-place =====
yq -i '.server.port = 9090' config.yaml
yq -i '.spec.replicas = 5' deploy.yaml

# ===== Merge multiple files =====
yq eval-all 'select(fileIndex == 0) * select(fileIndex == 1)' base.yaml override.yaml

# ===== Convert multi-document YAML to JSON array =====
yq -o=json -s '.' multi-doc.yaml

jq

jq는 YAML을 직접 처리하지 않지만 yq와 결합 가능:

# Pipe yq output through jq for advanced JSON processing
yq -o=json config.yaml | jq '.server'
yq -o=json deploy.yaml | jq '.spec.template.spec.containers[] | .name'

# Use jq to transform JSON, then convert to YAML
cat data.json | jq '{filtered: .items | map(select(.active))}' | yq -o=yaml -P

원라이너

# Python one-liner: YAML to JSON
python3 -c 'import sys,yaml,json; json.dump(yaml.safe_load(sys.stdin),sys.stdout,indent=2)' < config.yaml

# Python one-liner: JSON to YAML
python3 -c 'import sys,yaml,json; print(yaml.dump(json.load(sys.stdin),default_flow_style=False))' < config.json

# Ruby one-liner: YAML to JSON
ruby -ryaml -rjson -e 'puts JSON.pretty_generate(YAML.safe_load(STDIN.read))' < config.yaml

Kubernetes 매니페스트

Kubernetes는 YAML을 클라우드 네이티브의 공용어로 만들었습니다.

전형적인 Deployment 매니페스트:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-application
  namespace: production
  labels:
    app: web
    version: "2.0"         # Quoted to prevent float interpretation
    environment: production
  annotations:
    description: >-        # Folded block, strip trailing newline
      Production web application deployment
      with auto-scaling and health checks
spec:
  replicas: 3
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
    spec:
      containers:
        - name: web
          image: myregistry/web-app:2.0.1
          ports:
            - containerPort: 8080
              protocol: TCP
          env:
            - name: DATABASE_URL
              valueFrom:
                secretKeyRef:
                  name: db-credentials
                  key: url
            - name: LOG_LEVEL
              value: "info"        # Quoted to ensure string
          resources:
            requests:
              cpu: 100m
              memory: 128Mi
            limits:
              cpu: 500m
              memory: 512Mi
          livenessProbe:
            httpGet:
              path: /healthz
              port: 8080
            initialDelaySeconds: 30
            periodSeconds: 10
---
# Multiple resources in one file
apiVersion: v1
kind: Service
metadata:
  name: web-service
spec:
  selector:
    app: web
  ports:
    - port: 80
      targetPort: 8080
  type: ClusterIP

Kubernetes YAML 패턴: 중첩, 시퀀스, 다중행 문자열, 레이블.

Docker Compose와 CI/CD

Docker Compose와 GitHub Actions도 주요 YAML 생태계:

Docker Compose

# docker-compose.yml
services:
  app:
    build:
      context: .
      dockerfile: Dockerfile
      args:
        NODE_ENV: production
    ports:
      - "3000:3000"
    environment:
      - DATABASE_URL=postgres://user:pass@db:5432/myapp
      - REDIS_URL=redis://cache:6379
    depends_on:
      db:
        condition: service_healthy
      cache:
        condition: service_started
    volumes:
      - ./uploads:/app/uploads
    restart: unless-stopped

  db:
    image: postgres:16-alpine
    environment:
      POSTGRES_DB: myapp
      POSTGRES_USER: user
      POSTGRES_PASSWORD: pass
    volumes:
      - postgres_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U user -d myapp"]
      interval: 10s
      timeout: 5s
      retries: 5

  cache:
    image: redis:7-alpine
    command: redis-server --maxmemory 256mb --maxmemory-policy allkeys-lru

volumes:
  postgres_data:

GitHub Actions

GitHub Actions는 특정 YAML 패턴을 사용:

# .github/workflows/ci.yml
name: CI Pipeline

on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main]

jobs:
  test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        node-version: [18, 20, 22]
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node-version }}
          cache: npm
      - run: npm ci
      - run: npm test
      - run: npm run build

  deploy:
    needs: test
    if: github.ref == 'refs/heads/main'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Deploy to production
        env:
          DEPLOY_KEY: ${{ secrets.DEPLOY_KEY }}
        run: |
          echo "Deploying to production..."
          ./scripts/deploy.sh

무료 JSON-YAML 변환 도구 사용해보기

YAML 함정

YAML의 유연성에는 함정이 따릅니다:

노르웨이 문제

YAML의 가장 유명한 함정:

# YAML 1.1 boolean coercion (PyYAML, many other parsers)
# These ALL become booleans when unquoted:

countries:
  - US       # String "US" (ok)
  - GB       # String "GB" (ok)
  - NO       # BECOMES: false  (Norway disappears!)
  - FR       # String "FR" (ok)

settings:
  verbose: yes    # BECOMES: true  (not the string "yes")
  debug: no       # BECOMES: false
  feature: on     # BECOMES: true
  legacy: off     # BECOMES: false
  confirm: y      # BECOMES: true
  cancel: n       # BECOMES: false

# FIX: Always quote ambiguous values
countries:
  - "US"
  - "GB"
  - "NO"     # Now correctly a string
  - "FR"

settings:
  verbose: "yes"  # String "yes"
  debug: "no"     # String "no"

국가 코드 NOfalse가 됨. 해결: 따옴표 사용.

들여쓰기 오류

YAML은 공백만 사용(탭 불가). 에디터를 2칸 공백으로 설정:

# .editorconfig - enforce consistent YAML formatting
[*.{yml,yaml}]
indent_style = space
indent_size = 2
tab_width = 2
insert_final_newline = true
trim_trailing_whitespace = true

# .yamllint.yml - lint configuration
---
extends: default
rules:
  indentation:
    spaces: 2
    indent-sequences: true
  truthy:
    check-keys: true
    allowed-values: ["true", "false"]
  line-length:
    max: 120

예상치 못한 불리언

버전 번호 1.0이 부동소수점이 됨:

# More unexpected type coercions in YAML:

version: 1.0        # BECOMES: float 1.0 (not string "1.0")
version: "1.0"      # String "1.0" (correct)

octal: 0o17         # BECOMES: integer 15
hex: 0xFF           # BECOMES: integer 255

date: 2024-01-15    # BECOMES: date object (in some parsers)
date: "2024-01-15"  # String "2024-01-15" (correct)

null_trap: null      # BECOMES: null (not string "null")
null_trap: ~         # ALSO BECOMES: null
null_trap: ""        # Empty string (if you want empty, not null)

# Special float values
infinity: .inf       # BECOMES: Infinity
not_a_number: .nan   # BECOMES: NaN

# Rule of thumb: if it's not obviously a string, quote it

YAML 보안

YAML 파서는 위험할 수 있습니다.

위험 패턴: yaml.load(data)는 임의 객체 생성 가능.

# DANGEROUS - Never do this with untrusted YAML input!
import yaml

# This YAML payload can execute arbitrary commands:
malicious_yaml = """
!!python/object/apply:os.system
  args: ['echo HACKED > /tmp/pwned']
"""

# BAD: yaml.load() with FullLoader allows object construction
# data = yaml.load(malicious_yaml, Loader=yaml.FullLoader)  # DANGER!

# GOOD: safe_load() only allows basic types
data = yaml.safe_load(malicious_yaml)  # Raises ConstructorError

# ALSO GOOD: ruamel.yaml with safe type
from ruamel.yaml import YAML
safe_yaml = YAML(typ='safe')
data = safe_yaml.load(malicious_yaml)  # Raises error

안전 패턴: yaml.safe_load() 사용.

JavaScript js-yaml v4는 기본 안전.

입력 크기 제한, 스키마 검증, 신뢰할 수 없는 소스의 안전한 로딩 필수.

기능 비교표

JSON과 YAML의 종합 비교:

FeatureJSONYAML
SyntaxBraces {} and brackets []Indentation-based
CommentsNot supportedSupported with #
String QuotingRequired (double quotes)Optional for most strings
Multi-line StringsEscape with \nBlock scalars: | and >
Anchors / AliasesNot supportedSupported with & and *
Multiple DocumentsOne per fileYes, separated by ---
Data TypesString, Number, Boolean, null, Array, ObjectAll JSON types + dates, binary, custom tags
Parsing SpeedFast (simple grammar)Slower (indentation-sensitive)
File SizeLarger (quotes, braces)Smaller (minimal punctuation)
ToolingUniversal (every language)Good (PyYAML, js-yaml, yq)
Primary UseAPIs, data exchangeConfiguration files
Superset RelationBase formatSuperset of JSON

자주 묻는 질문

JSON과 YAML의 차이점은?

JSON은 중괄호와 엄격한 구문. YAML은 들여쓰기 기반으로 주석과 다중행 문자열 지원.

온라인에서 JSON을 YAML로 변환하려면?

온라인 도구에 JSON을 붙여넣으면 YAML로 변환됩니다.

설정 파일에 YAML이 JSON보다 나은가요?

네, 사람이 편집하는 파일에는 YAML이 적합합니다.

YAML의 노르웨이 문제란?

YAML 1.1이 NO를 false로 해석하는 문제. 따옴표로 해결.

yaml.safe_load()를 사용해야 하는 이유?

yaml.load()는 임의 코드 실행 위험. safe_load()는 기본 타입만 허용.

JSON 변환 후 YAML 주석이 보존되나요?

아니요. ruamel.yaml을 사용하세요.

CLI에서 변환하려면?

yq -o=json file.yaml 사용.

JSON 변환 시 손실되는 YAML 기능은?

주석, 앵커, 다중행 블록, 다중 문서, 날짜 타입.

JSON과 YAML의 관계를 이해하는 것은 현대 소프트웨어 개발에 필수적입니다.

무료 온라인 도구로 JSON과 YAML을 즉시 변환하세요.

𝕏 Twitterin LinkedIn
도움이 되었나요?

최신 소식 받기

주간 개발 팁과 새 도구 알림을 받으세요.

스팸 없음. 언제든 구독 해지 가능.

Try These Related Tools

Y{}JSON ↔ YAML Converter{ }JSON FormatterYMLYAML Validator & Formatter🐳Docker Compose Generator

Related Articles

YAML to JSON 변환기 완전 가이드: 코드 예제 포함

무료 온라인 YAML to JSON 변환기. YAML 구문 학습, YAML-JSON 변환, 일반적인 함정 회피를 JavaScript, Python, Go, Bash 코드 예제로 설명.

JSON vs YAML vs TOML: 어떤 설정 포맷을 사용해야 할까?

JSON, YAML, TOML 설정 포맷을 비교합니다.

YAML 문법 & 검증: 일반적인 오류와 해결 방법

YAML 문법 마스터: 들여쓰기 규칙, 파싱 오류, 데이터 타입, 모범 사례.

YAML 앵커, 별칭 및 병합 키

앵커(&), 별칭(*), 병합 키(<<)로 YAML DRY 원칙 마스터. Docker Compose, CI/CD, Kubernetes 설정의 중복 제거.