guide/json-diff.md

JSON 비교하는 법 — 키 순서 정렬과 정규화

JSON 두 개를 비교할 때 키 순서·들여쓰기·숫자 표기 차이 때문에 생기는 가짜 차이를 없애는 방법과 배열 순서, 큰 정수, JSON Patch 와의 차이를 설명합니다.

최종 수정: 2026-09-23

API 응답, 설정 파일, 번역 파일처럼 JSON 으로 된 데이터를 비교할 일은 자주 생깁니다. 그런데 두 JSON 을 그대로 텍스트 비교하면 데이터는 같은데도 차이가 잔뜩 나오는 경우가 많습니다. 이 글은 그 이유와 해결 방법을 설명합니다.

왜 가짜 차이가 생기나

JSON 표준(RFC 8259)은 객체를 "순서 없는 이름/값 쌍의 모음"으로 정의합니다. 즉 {"a":1,"b":2}{"b":2,"a":1} 은 같은 데이터를 뜻합니다. 하지만 텍스트로는 줄의 순서가 다르므로 diff 는 차이로 봅니다. 그 밖에도 다음 차이가 데이터와 무관하게 생깁니다.

해결: 파싱한 뒤 같은 모양으로 다시 쓰기

가장 확실한 방법은 두 JSON 을 파싱해서 데이터로 만든 다음, 같은 규칙으로 다시 직렬화하는 것입니다.

  1. 두 텍스트를 JSON 으로 파싱합니다. 여기서 문법 오류가 있으면 먼저 고칩니다.
  2. 모든 객체의 키를 재귀적으로 정렬합니다.
  3. 같은 들여쓰기(예: 2칸)로 다시 씁니다.
  4. 그 결과를 줄 단위로 비교합니다.

예를 들어 다음 두 JSON 은 키 순서만 다르고 배열 순서가 다릅니다.

{"name":"kim","age":30,"tags":["a","b"]}
{"age":30,"name":"kim","tags":["b","a"]}

정렬하고 다시 쓰면 키 순서 차이는 사라지고 진짜 차이인 배열 순서만 남습니다.

@@ -2,7 +2,7 @@   "age": 30,   "name": "kim",   "tags": [-    "a",-    "b"+    "b",+    "a"   ] }

배열 순서는 정렬하지 않는다

객체와 달리 배열은 순서가 의미를 가집니다. ["a","b"]["b","a"] 는 다른 데이터입니다. 그래서 정규화할 때 배열은 정렬하지 않는 것이 원칙입니다. 다만 태그 목록처럼 업무상 순서가 중요하지 않은 배열이라면, 비교 전에 직접 정렬하는 편이 결과를 읽기 쉽게 만듭니다. 어느 쪽이 맞는지는 데이터의 의미에 달려 있습니다.

파싱이 바꿔 버리는 것들

파싱 후 다시 쓰는 방법에는 알아 둘 부작용이 있습니다.

명령행에서 하는 방법

jq 가 설치돼 있다면 -S(--sort-keys) 옵션으로 키를 정렬해 출력할 수 있습니다.

jq -S . before.json > a.json
jq -S . after.json  > b.json
diff -u a.json b.json

JSON Patch 와의 차이

diff 결과는 사람이 읽기 위한 줄 단위 변경 목록입니다. 반면 JSON Patch(RFC 6902)는 {"op":"replace","path":"/age","value":31} 처럼 JSON 구조의 경로로 변경을 표현하는 표준이고, JSON Merge Patch(RFC 7396)는 바뀐 부분만 담은 JSON 을 원본에 덮어쓰는 방식입니다. 프로그램끼리 변경을 주고받는다면 이 표준들이, 사람이 검토한다면 정렬 후 텍스트 diff 가 알맞습니다.

이 도구에서 해 보기

텍스트 비교기의 옵션에서 JSON 키 정렬을 켜면, 양쪽을 파싱해 키를 정렬하고 2칸 들여쓰기로 다시 쓴 다음 비교합니다. 배열 순서는 바꾸지 않으며, 파싱에 실패하면 어느 쪽 몇 번째 글자에서 오류가 났는지 알려 줍니다. .json 파일 두 개를 한꺼번에 끌어다 놓아도 됩니다. 결과를 patch 로 읽는 법은 unified diff 읽는 법을 참고하세요.

텍스트 비교하러 가기