큰 숫자가 살아남습니다
정렬은 여러분이 붙여 넣은 자릿수를 그대로 다시 내보냅니다. float로 파싱했다가 다시 문자열로 만드는 도구는, 버튼을 누르기도 전에 이미 여러분의 스노플레이크 ID를 바꿔 놓았습니다.
여기서는
{ "id": 12345678901234567890 } JSON.parse로 왕복하면
{ "id": 12345678901234567000 } 페이로드를 붙여 넣으면 읽을 수 있게 돌려줍니다. 전부 브라우저 안에서 돌기 때문에 프로덕션 응답도, 토큰도, 설정 파일도 여러분의 컴퓨터를 벗어나지 않습니다.
붙여 넣은 것은 여러분의 브라우저를 떠나지 않습니다. connect-src 허용 목록 덕분에 이는 약속이 아니라 브라우저가 강제하는 보장입니다. 직접 확인하기
2025년 11월, 가장 큰 포매터 사이트 두 곳이 저장된 붙여넣기 8만 건 이상을 유출했습니다. 정부·의료·항공우주 조직의 Active Directory 자격 증명, 클라우드 키, 액세스 토큰, 은행 기록이었습니다. 그들의 첫 화면에는 데이터가 브라우저에서 처리된다고 적혀 있었습니다. 그리고 그들의 파일 업로드는 그 데이터를 서버로 보냈습니다.
오른쪽에 있는 헤더가 이 사이트가 모든 응답에 실어 보내는 것입니다. 그 connect-src 줄은 목적지 하나만 지정한 허용 목록입니다. 페이지 조회 수를 세는 애널리틱스 엔드포인트입니다. 이 페이지가 시도할 수 있는 그 밖의 모든 요청은 거부됩니다. 여러분의 페이로드를 어디론가 실어 나르는 fetch도, XHR도, WebSocket도, beacon도 안 됩니다. 우리 의도에 대한 주장이 아닙니다. 여기서 도는 모든 코드에 브라우저가 부과하는 규칙이고, 우리가 나중에 실수로 넣을 코드에도 적용됩니다.
Content-Security-Policy:
default-src 'self';
connect-src https://*.google-analytics.com https://*.analytics.google.com https://*.googletagmanager.com;
script-src 'self' https://www.googletagmanager.com;
style-src 'self' 'unsafe-inline';
img-src 'self' data: https://*.google-analytics.com https://*.googletagmanager.com;
font-src 'self';
form-action 'none';
frame-ancestors 'none';
base-uri 'self';
object-src 'none';
worker-src 'self' blob:
Referrer-Policy: no-referrer
X-Content-Type-Options: nosniff
Permissions-Policy: interest-cohort=(), browsing-topics=() 아래의 모든 예시는 이 파서의 실제 출력이고, 하나같이 JSON.parse를 감싼 포매터가 틀리는 것들입니다.
정렬은 여러분이 붙여 넣은 자릿수를 그대로 다시 내보냅니다. float로 파싱했다가 다시 문자열로 만드는 도구는, 버튼을 누르기도 전에 이미 여러분의 스노플레이크 ID를 바꿔 놓았습니다.
여기서는
{ "id": 12345678901234567890 } JSON.parse로 왕복하면
{ "id": 12345678901234567000 } 문서나 채팅 클라이언트에서 붙여 넣으면 눈에 보이지 않는 문자가 딸려 옵니다. 다른 도구는 Unexpected token이라고만 합니다.
4:8 Invalid whitespace:
no-break space (U+00A0). 파일이 잘려 있을 때 쓸모 있는 정보는 문서가 끝났다는 사실이 아니라, 열린 괄호 각각이 어디서 시작했는가입니다.
The document ends while 3 brackets
are still open: { opened at line 1,
column 1; [ opened at line 2, column 8;
{ opened at line 3, column 5. 관대 모드는 거의 JSON인 것을 고치고 가한 변경을 전부 나열하며, 안전한 것과 판단이 섞인 것을 나눠 보여 줍니다.
2:3 Converted a single-quoted string
to a double-quoted JSON string.
5:11 Quoted 02134 as the string
"02134", because dropping the
leading zero would change a
zip code. RFC 8259는 중복을 정의하지 않은 채 두고, 대부분의 파서는 조용히 마지막 것을 취합니다.
3:3 Duplicate key "email",
first defined at line 2,
column 3. 파싱과 정렬이 웹 워커에서 돌기 때문에, 큰 문서를 처리하는 동안에도 화면은 계속 반응합니다. 아래 수치는 정렬에 걸린 시간이고, 데스크톱 한 대에서 두 번 측정했습니다. 벤치마크가 아니라 범위로 봐 주세요. 10MB면 메인 스레드를 완전히 묶어 둘 만한 작업량이고, 그래서 여기서는 메인 스레드에서 하지 않습니다.
9 to 13 ms
100 KB
70 to 119 ms
1 MB
0.6 to 0.8 s
10 MB
{
"user": "priya",
"roles": ["admin",],
} 3:20 ] 앞에 끝 쉼표가 있습니다.
닫는 대괄호 앞의 쉼표를 지우세요. 끝 쉼표는 JavaScript와 JSON5에서는 합법이지만 JSON에서는 아닙니다.
V8은 2022년에 JSON 오류 메시지를 거의 전부 다시 썼는데, 인터넷에 쓰인 글의 대부분은 아직도 옛 문구를 가르칩니다. 이 페이지들은 파서를 직접 돌려 측정한 현행의 정확한 문자열을 담고, 실제로 일어나는 빈도순으로 진짜 원인을 정리했습니다.
Unexpected end of JSON input "[object Object]" is not valid JSON Bad control character in string literal in JSON at position N (line L column C) Expected double-quoted property name in JSON at position N (line L column C) Expecting value: line 1 column 1 (char 0) Unexpected token '<', "<!DOCTYPE "... is not valid JSON JSON beautifier는 문서를 읽어 객체, 배열, 문자열, 숫자, 불리언, null로 이루어진 트리로 파싱한 다음, 그 트리를 한 줄에 값 하나씩 일정한 들여쓰기로 다시 써냅니다. 중요한 단어는 파싱입니다. 정규식으로 쉼표마다 줄바꿈을 끼워 넣는 것이 아닙니다. 웹에 돌아다니는 적지 않은 코드 조각이 그렇게 하고 있고, 그 방식은 쉼표나 중괄호가 들어 있는 문자열을 조용히 망가뜨립니다.
여기서 곧바로 만나게 되는 결과가 있습니다. 올바른 JSON이 아닌 문서는 정렬할 수 없습니다. 출력할 트리 자체가 없기 때문입니다. 이 사이트에서 정렬과 검증이 버튼 두 개가 아니라 같은 동작인 이유가 그것이고, 잘못된 내용을 붙여 넣었을 때 빈 출력창 대신 줄과 열, 그리고 무엇이 와야 했는지에 대한 설명이 돌아오는 이유도 그것입니다.
문자열 바깥의 공백은 JSON에서 아무 의미도 없습니다. RFC 8259는 어떤 두 토큰 사이에도 공백, 탭, 캐리지 리턴, 줄바꿈을 허용하므로 다시 포맷한다고 해서 문서의 의미가 달라지지 않습니다. 반면 문자열 안쪽의 공백은 데이터이며 있던 그대로 남습니다. 구문 트리가 아니라 텍스트를 대상으로 동작하는 포매터는 이 두 경우를 구분하지 못하고, 그것이 포맷 과정에서 페이로드가 망가지는 가장 흔한 경로입니다.
키 순서는 그대로 유지됩니다. 명세는 객체를 순서 없는 것으로 규정하므로 어떤 것도 순서에 의존해서는 안 되지만, 붙여 넣은 순서는 diff와 코드 리뷰와 읽는 사람이 거의 언제나 기대하는 순서입니다. 키를 재정렬하면 이후의 모든 비교가 이유 없이 시끄러워질 뿐, 얻는 것이 없습니다.
왼쪽 패널에 붙여 넣고 정렬을 누르세요. 포맷된 문서가 오른쪽에 나타나고, 바로 복사하거나 내려받을 수 있습니다. 계정도, 업로드 단계도, 하루 사용량 제한도, 어디에도 결제 장벽도 없습니다. JSON beautifier를 온라인 무료로 찾는 사람들이 원하는 것은 데스크톱 제품의 체험판이 아니라 대개 이것입니다.
기본 들여쓰기는 공백 두 칸으로, 대부분의 언어 생태계와 스타일 가이드가 자리 잡은 값입니다. 저장소에서 이미 정해 두었다면 네 칸과 탭도 고를 수 있고, 그 선택은 서버가 아니라 브라우저에 로컬로 기억됩니다. 기억해 둘 서버가 아예 없기 때문입니다.
모든 처리가 웹 워커 안에서 돌아가므로 문서를 파싱하는 동안에도 화면은 계속 반응합니다. 100 KB 페이로드는 약 9~13 ms, 1 MB는 70~119 ms, 10 MB는 약 0.6~0.8초에 포맷됩니다. 데스크톱 한 대에서 두 번 측정한 값이니 벤치마크가 아니라 범위로 받아들이시되, 중요한 것은 규모입니다. 10 MB는 메인 스레드를 완전히 얼어붙게 만들기에 충분한 작업량이고, 여기서는 메인 스레드에서 돌지 않습니다.
첫 방문 이후 페이지가 캐시되므로 이 온라인 JSON beautifier는 네트워크를 끊어도 계속 동작합니다. 서비스 워커를 이용한 요령이 아닙니다. 모든 일을 로컬에서 처리하는 정적 페이지의 자연스러운 결과입니다. 네트워크가 없으면 애널리틱스 핑은 그냥 실패하고, 모든 도구는 그대로 돌아갑니다. 애초에 어느 것도 서버가 필요하지 않았기 때문입니다.
대부분의 포매터는 텍스트 영역과 버튼 하나입니다. 붙여 넣은 것이 들어가고 포맷된 텍스트가 나오며, 문서가 깨져 있었다면 다시 자기 에디터로 돌아가 짐작을 시작하게 됩니다. 여기의 패널은 구문 강조, 괄호 짝 표시, 코드 접기, 증분 검색, 줄 안의 오류 표시를 갖춘 진짜 코드 에디터입니다. 붙여 넣은 것을 그 자리에서 고치고 페이지를 떠나지 않은 채 다시 포맷할 수 있습니다.
접기는 들리는 것보다 훨씬 중요합니다. 4,000줄짜리 설정 파일은 들여쓰기가 되었다는 이유만으로 읽히지 않습니다. 실제로 읽히게 만드는 것은 관심 있는 가지 하나만 남기고 나머지를 모두 접는 일이고, 그것은 포매터가 아니라 에디터의 성질입니다.
같은 문서를 텍스트가 아니라 접을 수 있는 트리로 보고 싶다면 JSON 뷰어가 그렇게 보여 줍니다. 검증은 첫 번째에서 멈추지 않고 모든 문제를 보고합니다. 복구는 작은따옴표, 끝에 남은 쉼표, 따옴표 없는 키 같은 거의-JSON을 다루고, 수행한 모든 변경을 나열해 수정이 아니라 판단이 개입된 것들만 되돌릴 수 있게 합니다.
최고의 JSON 뷰어 겸 JSON beautifier를 온라인에서 찾는 사람이 실제로 묻는 것은, 어느 도구나 제대로 해내는 들여쓰기가 아닙니다. 도구를 깨뜨리는 문서에 대한 질문입니다. JavaScript가 담을 수 있는 범위를 넘는 정수, 중복 키, 채팅 클라이언트나 워드프로세서에서 딸려 온 보이지 않는 문자. 그것들이 여기서 처리되고 위쪽 카드에 실제 출력으로 설명되어 있으며, 논쟁할 가치가 있는 부분은 그것뿐입니다.
브라우저 탭이 언제나 이 일을 하고 싶은 자리인 것은 아닙니다. 파일이 이미 에디터에 열려 있다면 가장 빠른 JSON beautifier는 거기서 단축키에 걸려 있는 것입니다.
Notepad++에는 JSON 포매터가 내장되어 있지 않습니다. 흔한 답은 JSTool 플러그인입니다. Plugins에서 Plugins Admin을 열어 JSTool을 검색해 설치하고 재시작하면 Plugins, JSTool, JSFormat에 명령이 생깁니다. 잘 동작하고 일상적인 페이로드에는 이것이 맞는 도구입니다. 다만 JSTool은 숫자를 64비트 부동소수점으로 파싱하므로 9007199254740991을 넘는 트위터나 스노플레이크 방식의 ID는 들어갈 때와 다른 자릿수로, 아무 말 없이 돌아옵니다.
Sublime Text는 Pretty JSON 패키지를 씁니다. Package Control로 설치하면 기본적으로 Ctrl+Alt+J에 연결됩니다. Python을 거쳐 포맷하기 때문에 큰 정수가 정확히 살아남고, 이는 JavaScript 기반 선택지들에 대한 실질적인 장점입니다. 대신 중복 키는 아무 말 없이 버리고 마지막 것만 남깁니다.
VS Code는 플러그인이 아예 필요 없습니다. 문서 서식, 즉 Windows와 Linux에서는 Shift+Alt+F, macOS에서는 Shift+Option+F가 에디터가 JSON으로 인식한 파일을 포맷합니다. 명령 팔레트에는 Format JSON이라는 전용 명령도 있습니다.
이들 중 어느 것도 주지 않는 것이 진단입니다. 유효한 문서를 포맷하고 무효한 문서를 거부합니다. 문서가 무효하면서 4만 줄이 되는 날이 오기 전까지는 그것으로 충분합니다. 이 페이지는 바로 그 상황을 위해 만들어졌고, 플러그인 설치가 허용되지 않는 컴퓨터도 마찬가지입니다.
Chrome의 JSON beautifier 확장 프로그램은 분명히 쓸모 있는 일을 합니다. application/json으로 내려오는 응답을 가로채 주소창에서 포맷되고 접을 수 있는 형태로 그려 주므로, 만지고 있는 API를 포매터까지 왕복하지 않고도 읽을 수 있습니다. Firefox는 44 버전부터 같은 일을 기본으로 해 왔고 그 용도로는 확장 프로그램이 전혀 필요하지 않습니다.
설치하기 전에 대가를 읽어 볼 가치가 있습니다. 방문하는 모든 API의 페이지를 다시 쓰려면 확장 프로그램은 모든 웹사이트에서 사용자의 데이터를 읽고 변경할 권한을 요청해야 합니다. Chrome이 부여하는 가장 넓은 권한입니다. 그 권한은 은행과 메일과 회사의 관리자 콘솔까지 포함하고, 이후 확장 프로그램이 내보내는 모든 조용한 업데이트를 건너뛰며 그대로 유지됩니다. 신뢰할 이유가 있는 개발자가 만든 JSON beautifier 확장 프로그램을 설치하는 것은 합리적이지만, 검색 결과 맨 위에 있었다는 이유로 설치하는 것은 그렇지 않습니다.
이 페이지에는 그중 아무것도 필요하지 않습니다. Chrome, Firefox, Safari, Edge에서 똑같이 동작하고, 아무것도 설치하지 않으며, 여러분이 방문하는 다른 어떤 사이트에 대해서도 권한을 보유하지 않습니다. 페이지는 확장 프로그램이 아니기 때문입니다. 페이지가 읽을 수 있는 것은 자기 자신뿐이고 그 밖에는 아무것도 없습니다. 가로채는 확장 프로그램과의 차이는 붙여넣기 한 번뿐입니다.
이 일에는 라이브러리가 필요 없습니다. JSON.stringify에는 들여쓰기를 제어하는 세 번째 인자가 있고 모든 JavaScript 런타임에 들어 있습니다. JSON.stringify(value, null, 2)는 공백 두 칸으로 들여쓰고, 숫자 대신 문자열을 넘기는 JSON.stringify(value, null, "\t")는 탭으로 들여씁니다.
결과를 페이지에 넣는 지점이 바로 HTML에서의 JSON beautifier가 어긋나는 곳입니다. 출력은 <pre> 요소 안에 들어가야 하고, 그렇지 않으면 연속된 공백이 무너져 포맷이 도로 사라집니다. 그리고 HTML로 삽입하기 전에 반드시 이스케이프해야 합니다. 그러지 않으면 </script>나 꺾쇠를 담은 문자열 값을 마크업으로 파서에 넘기는 셈이 되고, 그것은 단계만 몇 개 더 붙은 크로스 사이트 스크립팅 구멍입니다.
React에서는 그 이스케이프가 이미 되어 있습니다. 디버깅 목적이라면 <pre>{JSON.stringify(data, null, 2)}</pre>가 React JSON beautifier의 전부이고, React가 보간된 텍스트를 기본으로 이스케이프하므로 신뢰할 수 없는 입력에도 안전합니다. 규칙은 단순합니다. JSON을 그리기 위해 dangerouslySetInnerHTML에 손대지 않는 것. 그 보장을 잃는 길은 그것 하나뿐입니다.
이 모든 경우에 공통으로 붙는 단서는 수치 정밀도입니다. JSON.parse는 모든 숫자를 double로 바꾸므로 2^53-1을 넘는 식별자는 JSON.stringify가 보기도 전에 이미 다른 숫자가 되어 있고, 어떤 포맷도 그 자릿수를 되돌려 주지 않습니다. 페이로드에 큰 ID가 실린다면 먼저 2^53-1을 넘는 정수에 무슨 일이 일어나는지를 읽어 보세요. 이 페이지의 beautifier는 붙여 넣은 자릿수를 그대로 다시 내보냅니다. 그 출력과 JSON.parse 왕복의 결과가 늘 일치하지는 않는 이유가 그것입니다.