JSON 키 정렬
중첩된 객체까지 키를 알파벳순으로 정렬해, diff가 깔끔하게 유지됩니다.
붙여 넣은 것은 여러분의 브라우저를 떠나지 않습니다. connect-src 허용 목록 덕분에 이는 약속이 아니라 브라우저가 강제하는 보장입니다. 직접 확인하기
객체의 키를 알파벳순으로, 중첩된 모든 객체를 따라 재귀적으로 정렬합니다. 배열의 순서는 절대 건드리지 않습니다. 배열의 순서는 의미가 있고 객체 키의 순서는 없기 때문입니다.
이렇게 하는 이유는 diff입니다. 내용이 같고 키 순서만 다른 두 파일은 잡음투성이 diff를 만듭니다. 둘 다 정렬하면 diff에는 정말로 바뀐 것만 남습니다.
정렬이 옳은 선택일 때
- 생성된 파일을 커밋하기 전
- 락 파일, 내보낸 설정, 도구가 써 내는 모든 것. 생성기가 순서를 보장하지 않는다면, 정렬이 실행마다 그리고 머신마다 파일을 안정적으로 만들어 줍니다.
- 두 문서를 비교하기 전
- 먼저 둘 다 정렬하면 텍스트 diff가 읽을 만해집니다. 저희 구조 diff는 어차피 키 순서를 무시하므로, 이건 주로 그렇지 않은 도구를 위한 것입니다.
- 정규형을 얻기 위해
- 문서를 해시하거나 서명하려면 결정적인 직렬화가 필요합니다. 키 정렬은 그 일부이고, 나머지는 RFC 8785(JSON Canonicalization Scheme)가 숫자 표기와 문자열 이스케이프까지 포함해 규정합니다.
정렬이 잘못된 선택일 때
순서가 읽는 사람에게 의미를 갖는, 손으로 관리하는 설정 파일. 중요한 설정이 위에 있고 관련된 것끼리 묶여 있는 경우입니다. 그걸 알파벳순으로 정렬하는 건 기술적으로는 무해하고 실무적으로는 성가십니다.
받아 쓰는 쪽이 키 순서에 의존하는 모든 경우도 그렇습니다. 그래서는 안 되지만 직접 만든 파서 중에는 그런 것이 있고, 그 사실을 운영에서 알게 되면 비쌉니다.
비교 방식
기본값은 대소문자를 구분하며, 코드포인트 순서에 따라 대문자가 소문자보다 앞에 옵니다. 이름 목록에서 사람들이 흔히 기대하는 순서를 원한다면 대소문자를 구분하지 않는 비교를 켜세요.
이것은 로캘을 고려한 정렬이 아니라 코드포인트 정렬이라는 점에 유의하세요. 어디서든 결정적으로 같은 결과가 나오고, 정규형에는 바로 그 성질이 필요합니다. 로캘을 따르는 정렬은 머신마다 다른 파일을 만들어 냅니다.
How to do this in code
코드에서 키를 정렬하는 방법.
sh jq
-S는 최상위뿐 아니라 모든 단계에 적용됩니다.
jq -S . input.json # sort keys, recursively
jq -S -c . input.json # sorted and compact py Python
import json
# sort_keys applies recursively
out = json.dumps(json.loads(text), sort_keys=True, indent=2) js JavaScript
JavaScript에는 정렬된 stringify가 내장되어 있지 않습니다. 이 코드 조각이 그토록 자주 복사되는 이유입니다.
// The replacer only receives keys, so sorting needs a walk.
function sortDeep(value) {
if (Array.isArray(value)) return value.map(sortDeep);
if (value && typeof value === 'object') {
return Object.fromEntries(
Object.keys(value).sort().map((k) => [k, sortDeep(value[k])]),
);
}
return value;
}
const out = JSON.stringify(sortDeep(JSON.parse(text)), null, 2); go Go
표준 라이브러리가 시키지 않아도 옳은 일을 해 주는 드문 경우 중 하나입니다.
// encoding/json sorts map keys automatically when marshalling
// a map. Struct fields keep their declaration order.
var v map[string]any
json.Unmarshal(data, &v)
out, _ := json.MarshalIndent(v, "", " ") // keys sorted 자주 묻는 질문
- 정렬하면 데이터가 바뀌나요?
- 의미상으로는 아닙니다. 명세상 JSON 객체는 순서가 없으므로 정렬된 문서도 같은 값을 담습니다. 바이트는 바뀌는데, 그게 바로 목적입니다.
- 배열 요소는 왜 정렬하지 않나요?
- 배열의 순서가 데이터의 일부이기 때문입니다. [3,1,2]를 [1,2,3]으로 만드는 건 서식을 바꾸는 게 아니라 문서를 바꾸는 일입니다.
- 이게 정규화 JSON과 같은 건가요?
- 그 일부입니다. RFC 8785(JSON Canonicalization Scheme)는 숫자 표기, 문자열 이스케이프, 유니코드 정규화까지 규정하며, 결과를 해시하거나 서명할 생각이라면 모두 중요합니다.