쉼표 하나 때문에 새벽 3시까지 야근한 이야기 — JSON 포맷팅 실전 가이드
설정 파일에 쉼표 하나 잘못 들어갔다가 결제 서비스가 47분 동안 죽었던 경험이 있어요. 이 글에서는 그런 사고가 다시 안 나도록, JSON 문법 규칙부터 흔한 실수, YAML과의 비교, 대용량 파일을 터미널에서 다루는 jq 사용법까지 전부 정리했어요.
이 글에서 알 수 있는 것
- ✅JSON이 자바스크립트보다 훨씬 엄격한 이유 — 경력자도 자주 걸리는 문법 함정 총정리
- ✅JSON vs YAML vs TOML vs Protocol Buffers: 상황별로 어떤 포맷을 써야 하는지 비교표
- ✅수십 MB짜리 JSON 파일을 에디터 없이 터미널에서 다루는 jq 실전 명령어
금요일 오후였어요. 최악의 타이밍이죠. 결제 서비스 설정 파일에 기능 플래그 하나를 추가했어요. 깊게 중첩된 JSON 객체 안에 속성 하나 더 넣은 거라 변경량은 세 줄 정도였고, 리뷰도 통과했어요. 배포 나갔고요. 3분 후에 온콜 알람이 울렸어요. 결제 엔드포인트가 전부 500을 뱉고 있었거든요. 원인을 찾아보니 마지막 속성 뒤에 쉼표 하나가 있었어요. 그냥 후행 쉼표. 파서가 에러 없이 빈 설정값으로 폴백했고, 결제 로직 전체가 멈췄어요. 47분 롤백, 포스트모텀, 팀장님 한 마디. "쉼표 하나예요." 맞아요. 그 쉼표 하나가 일이에요.
JSON이 자바스크립트보다 훨씬 까다로운 이유
JSON이 자바스크립트랑 비슷하게 생겨서 같은 규칙이라고 생각하기 쉬운데, 전혀 달라요. JSON은 RFC 8259 명세로 정의된 독립적인 포맷이에요. 후행 쉼표 없음. 주석 없음. 작은따옴표 없음. 따옴표 없는 키 없음. undefined 없음. NaN 없음. Infinity 없음. 이 중 하나라도 들어가면 파싱 에러예요. 경고도 없고, 폴백도 없어요. 그냥 던져요. 왜 이렇게 엄격하냐고요? 어떤 언어에서든 기계가 읽을 수 있는 형식을 만들려면 모호함이 없어야 하거든요. 이 엄격함이 JSON을 언어 간 데이터 교환의 표준으로 만들었어요.
// 전부 잘못된 JSON — SyntaxError 납니다:
{
name: "민재", // 키는 큰따옴표로 감싸야 해요
'city': '서울', // 작은따옴표 안 돼요
"score": undefined, // undefined는 JSON 값이 아니에요
"ratio": NaN, // NaN도 안 돼요
"tags": ["js", "ts",], // 배열 마지막 쉼표 금지
"meta": { "v": 1, }, // 객체 마지막 쉼표 금지
// 이 주석도 파싱 에러 냅니다
}
// 올바른 JSON:
{
"name": "민재",
"city": "서울",
"score": null,
"ratio": 0.95,
"tags": ["js", "ts"]
}배포 파이프라인에 jq 한 줄 넣어두세요
CI 빌드 스텝에 jq . config.json 한 줄만 추가해두면 잘못된 JSON이 배포되는 걸 막을 수 있어요. 실행 시간 50밀리초짜리 명령어가 47분짜리 장애를 막아줘요. 핑계 없어요, 그냥 넣으세요.
실제로 중요한 포맷팅 규칙 7가지
2칸이냐 4칸이냐 같은 스타일 논쟁은 사실 크게 중요하지 않아요. 진짜 합의가 있는 규칙들만 정리했어요:
- 들여쓰기 2칸: JSON 업계 표준이에요. 4칸도 틀리진 않지만, 대부분의 포맷터와 개발자가 2칸을 기대해요.
- 큰따옴표 필수: 키도, 문자열 값도 전부 큰따옴표예요. 작은따옴표는 명세 위반이에요.
- 후행 쉼표 절대 금지: 배열 마지막 요소 뒤, 객체 마지막 속성 뒤에 쉼표 없어야 해요. JSON 파서는 무조건 에러 냅니다.
- undefined 대신 null: undefined는 자바스크립트 개념이에요. JSON에서 값이 없으면 null 써요.
- 속성 순서 일관성: JSON 스펙은 순서를 강제하지 않지만, 사람이 읽을 파일이라면 알파벳순이나 논리적 그룹핑을 유지하는 게 좋아요.
- 짧은 배열은 한 줄로: ["en", "ko", "ja"] 이런 건 세 줄 쓸 필요 없어요. 줄 길이 기준으로 판단하면 돼요.
- 중첩 객체는 들여쓰기 블록으로: 복잡한 중첩 구조를 한 줄에 압축하면 나중에 읽을 사람이 힘들어요.
지금 이 도구를 사용해 보세요:
JSON 포맷터 →JSON vs YAML vs TOML vs Protocol Buffers — 언제 뭘 써요?
JSON이 항상 최선은 아니에요. 상황별 포맷 선택 기준을 정리했어요:
| 포맷 | 주요 용도 | 사람이 쓰기 편한가 | 주석 지원 | 용량 |
|---|---|---|---|---|
| JSON | API, 데이터 교환, 범용 설정 | 보통 | 없음 | 기준 |
| YAML | 쿠버네티스, CI/CD, 복잡한 설정 | 좋음 | 있음 (#) | JSON과 유사 |
| TOML | 앱 설정 파일 (Rust, Python 프로젝트) | 좋음 | 있음 (#) | 약간 작음 |
| Protocol Buffers | 고성능 마이크로서비스 통신 | 없음 (바이너리) | .proto 파일에 | 3~10배 작음 |
| MessagePack | 실시간 앱, 게임, 대용량 바이너리 | 없음 (바이너리) | 없음 | 2~4배 작음 |
실무 기준으로 정리하면 이래요. 언어 경계를 넘거나 프로덕션 로그에서 사람이 직접 읽어야 하는 데이터면 JSON이에요. 사람이 자주 직접 수정하는 설정 파일은 YAML이 낫고요. 하루에 수백만 건 이상 메시지를 주고받는 마이크로서비스 간 통신이라면 Protocol Buffers를 고려할 만해요. 대부분의 웹 서비스는 JSON으로 충분해요.
대용량 JSON 파일 — 에디터 없이 다루기
VS Code는 5~10MB 정도부터 슬슬 버티기 시작해요. 50MB짜리 API 응답 덤프를 열면 몇 초 동안 멈추고, '파일이 너무 큽니다' 경고가 뜨고, 구문 강조도 꺼져요. 이럴 때 쓰는 게 jq예요.
# 대용량 JSON 예쁘게 출력하기 (에디터 없이)
jq . large-file.json
# 중첩 필드 값만 꺼내기
jq '.data.users[0].email' large-file.json
# 조건으로 배열 필터링
jq '.items[] | select(.status == "active")' large-file.json
# 배열 요소 수 세기
jq '.results | length' large-file.json
# 특정 필드의 고유값 목록
jq '[.items[].category] | unique' large-file.json
# 압축 출력 (minify)
jq -c . large-file.json
# 스트리밍 모드 (수백 MB 파일도 메모리 걱정 없이)
jq -cn --stream 'fromstream(1|truncate_stream(inputs;1))' huge.jsonJSON에 바이너리 데이터를 그냥 넣으면 안 돼요
JSON은 텍스트 포맷이라서 이미지, PDF, 오디오 같은 바이너리 데이터를 직접 넣으면 깨져요. 바이너리를 JSON에 담을 때는 반드시 Base64로 인코딩해서 문자열로 넣어야 해요. 크기가 33% 늘어나는 오버헤드가 생기지만, 텍스트 포맷의 한계예요. 대용량 파일이면 JSON에 인라인으로 넣지 말고 URL 참조로 처리하는 게 나아요.
배포 사고를 막는 JSON 검증 워크플로
수동으로 JSON 검증하는 건 믿을 수 없어요. 내가 아무리 꼼꼼해도 눈은 원하는 걸 보거든요. 실제로 효과 있는 자동화 워크플로를 공유할게요:
- 에디터 레벨: VS Code는 JSON 언어 서버가 기본 내장돼 있어요. 타이핑하는 순간 구문 에러가 빨간줄로 표시됩니다. 이걸 쓰지 않을 이유가 없어요.
- 커밋 훅: git pre-commit 훅에서 변경된 JSON 파일마다 jq . 실행해요. 검증 실패하면 커밋이 막혀요.
- CI 파이프라인: 빌드 단계에서 모든 설정 JSON 파일 검증해요. 잘못된 JSON이 메인 브랜치에 병합되면 안 돼요.
- 런타임 에러 핸들링: 외부에서 오는 JSON을 읽는 모든 코드에서 try/catch 안에 JSON.parse()를 써요. 파싱 에러가 나면 원본 입력값도 같이 로그에 남겨야 디버깅이 가능해요.
- 스키마 검증: 복잡한 API는 문법만 맞다고 끝이 아니에요. ajv 같은 라이브러리로 JSON Schema 검증을 추가하면 구조와 타입까지 자동으로 확인해줘요.
포맷팅이고 검증이고 다 해봐야 몇 초예요. 그게 막아주는 장애는 몇 시간이고요. 귀찮아도 해두는 게 맞아요.
자주 묻는 질문
자주 묻는 질문
JSON에 주석 달 수 없나요?
표준 JSON은 주석을 지원하지 않아요. 설정 파일에 주석이 필요하다면 YAML이나 TOML을 쓰는 게 맞아요. VS Code의 settings.json 같은 파일은 JSONC라는 비표준 확장을 쓰는데, 일반 JSON 파서에서는 에러가 나요. 주석이 꼭 필요한 JSON이라면 README 파일에 설명을 따로 쓰거나, 설정 키 이름을 보다 명확하게 짓는 게 나아요.
자바스크립트에서는 파싱되는데 파이썬에서 에러가 나요. 왜요?
자바스크립트 JSON.parse()가 일부 엣지 케이스에서 너그러운 경우가 있어요. 파이썬의 json.loads()는 더 엄격하게 구현돼 있고요. 한쪽에서 통과했다고 JSON이 올바른 게 아니에요. RFC 8259 표준 JSON을 만드는 게 맞아요. 큰따옴표, 후행 쉼표 없음, 주석 없음, undefined 없음. 이 기준 지키면 어느 파서에서도 통과해요.
브라우저에서 처리할 수 있는 JSON 파일 크기 한계가 어떻게 돼요?
메모리상으로는 50~100MB도 파싱되긴 해요. 근데 대용량 파일 파싱은 메인 스레드를 블록하기 때문에 UI가 멈춰요. 1MB 넘는 파일은 Web Worker 안에서 파싱하거나, 서버에서 페이지네이션해서 내려주는 게 맞아요. QuickFigure JSON 포맷터는 간단한 포맷팅 작업에는 충분히 써요.
프로덕션 API는 JSON을 압축해서 내보내야 하나요?
예. minified JSON이 30% 정도 작아요. 거기에 gzip이나 brotli 압축까지 적용하면 실제 전송 크기 차이가 꽤 커요. 사람이 직접 편집하는 설정 파일은 예외로 포맷팅된 형태를 유지하고요.
데이터베이스에 JSON을 그냥 저장해도 되나요?
PostgreSQL, MySQL 5.7+, MongoDB 같은 최신 DB는 JSON 컬럼을 네이티브로 지원하고 인덱싱이나 쿼리도 돼요. 스키마가 유연하게 바뀌는 데이터에는 JSON 컬럼이 편해요. 반면 구조가 고정된 데이터는 관계형 테이블이 쿼리 성능이나 인덱스 활용 면에서 훨씬 효율적이에요. 실무에서는 핵심 엔티티는 테이블, 메타데이터나 추가 속성은 JSON 컬럼으로 쓰는 조합이 많아요.
▶이 글에서 다룬 도구 바로 사용하기
민재
개발자 겸 테크 라이터. 개발 도구와 파일 변환 기술을 깊이 있게 다룹니다.
이 글이 도움이 되셨나요? 새 가이드 알림 받기
스팸 없이, 새 소식만 보내드립니다. 언제든 취소 가능. · 구독 시 개인정보처리방침에 동의합니다.