← 전체 글

JSON 미니파이 방법 —— 그리고 언제 해야 하나

JSON 미니파이는 파일 크기를 줄이고 API 응답을 빠르게 하려 모든 불필요한 공백을 제거. JavaScript, Python, 명령줄, 브라우저에서의 방법 —— 그리고 굳이 안 해도 될 때.

JSON은 설계상 공백에 관대합니다. JSON 뷰티파이어는 기계가 만든 압축 문자열을 들여쓰기로 펼쳐 사람이 읽기 좋은 출력으로 만들어 줍니다. JSON 미니파이어는 정반대로 — 그 공백을 모두 다시 벗겨내 파일 크기를 줄입니다. 두 작업 모두 데이터 자체는 전혀 바꾸지 않고 공백만 다릅니다. 이 가이드는 언제 뷰티파이하고 언제 미니파이할지, 그리고 둘 다 어떻게 할지를 다룹니다 — JavaScript, Python, 명령줄, 그리고 브라우저에서 바로.

JSON을 미니파이하면 실제로 무엇이 일어나나

이 정형화된 JSON 객체를 봅시다:

{
  "user": {
    "id": 42,
    "name": "Alice",
    "roles": [
      "admin",
      "editor"
    ],
    "active": true
  }
}

미니파이 후:

{"user":{"id":42,"name":"Alice","roles":["admin","editor"],"active":true}}

두 문자열은 의미상 동일합니다. 어떤 JSON 파서도 같은 데이터로 취급합니다. 미니파이 버전은 73자이고 정형 버전은 110자입니다. 34% 감소 — JSON이 커지고 중첩이 깊어질수록 격차는 벌어집니다.

제거되는 것: 모든 줄바꿈, 모든 들여쓰기용 공백과 탭, 키와 값을 구분하는 : 주변의 공백, 항목을 구분하는 , 다음 공백.

절대 제거되지 않는 것: 문자열 값 안쪽의 공백("hello world"은 그대로 "hello world"), 그리고 실제 데이터: 키, 값, 구조 문자.

반대: JSON 뷰티파이어란?

JSON 뷰티파이어 — JSON 포매터 또는 JSON 프리티프린터라고도 — 는 미니파이어의 반대를 합니다. 압축되어 읽기 힘든 JSON을 일관된 들여쓰기와 줄바꿈으로 펼쳐 사람 독자가 구조를 즉시 파악할 수 있게 합니다.

이 맥락에서 「beautify」, 「format」, 「pretty-print」, 「indent」는 모두 같은 뜻입니다. 출력은 입력과 의미상 동일하며 공백만 바뀝니다.

// 미니파이(API나 로그에서 받는 것)
{"order":{"id":1001,"items":[{"sku":"A1","qty":2},{"sku":"B3","qty":1}],"total":49.99}}

// 뷰티파이(2칸 들여쓰기)
{
  "order": {
    "id": 1001,
    "items": [
      { "sku": "A1", "qty": 2 },
      { "sku": "B3", "qty": 1 }
    ],
    "total": 49.99
  }
}

언제 JSON을 뷰티파이할까

가장 흔한 상황은 미니파이의 반대입니다: 압축된 JSON을 받았는데 — API 응답, 로그 파일, DB 익스포트, 동료의 메시지 — 읽거나 편집해야 할 때입니다.

  • API 응답 디버깅 — 미니파이된 응답은 훑어보기가 거의 불가능. 뷰티파이는 1초면 끝나고 모든 키가 보인다
  • 설정 파일 편집 — JSON 설정 변경을 커밋하기 전에 뷰티파이하면 diff가 읽기 쉽고 리뷰어가 무엇이 바뀌었는지 따라갈 수 있다
  • 데이터 구조 문서화 — README, 위키, PR 설명에 있는 정형 JSON은 한 줄짜리보다 훨씬 구조를 잘 전달한다
  • 낯선 데이터 살펴보기 — 새 API나 처음 보는 데이터셋을 다룰 때 먼저 뷰티파이하면 형태가 한눈에 들어온다
  • 깨진 JSON 고치기 — 뷰티파이는 부수 효과로 JSON을 검증한다. 출력이 이상하거나 오류가 보이면 입력에 문법 문제가 있다

fixjson으로 JSON 뷰티파이하기

fixjson의 JSON 뷰티파이어는 유효한 JSON과 깨진 JSON을 모두 처리합니다 — 대부분의 포매터가 못 하는 일입니다. 사용법:

  1. JSON을 붙여넣기 왼쪽 입력 패널에. 미니파이됐든, 부분 정형이든, 심지어 깨져도 됨(후행 쉼표, 작은따옴표, 따옴표 없는 키 — 모두 허용).
  2. 출력이 즉시 표시 오른쪽에 2칸 들여쓰기로 뷰티파이됨. 버튼 누를 필요 없음 — 입력에 따라 즉시 갱신.
  3. 들여쓰기 조정 필요하다면. 들여쓰기 선택기로 2칸, 4칸, 탭을 전환해 프로젝트 스타일에 맞출 수 있음.
  4. 결과 복사, 출력 패널 헤더의 복사 버튼을 쓰거나 전체 선택해 붙여넣기.

JSON에 오류가 있으면 fixjson이 뷰티파이 전에 자동으로 고칩니다 — 후행 쉼표 제거, 작은따옴표를 큰따옴표로 변환, 빠진 괄호 닫기. 덕분에 LLM, Python REPL, 로그 파일의 원시 출력을 그대로 붙여 넣어도 깔끔하게 정형된 JSON을 돌려받을 수 있고, 일일이 손으로 고칠 필요가 없습니다.

모든 것이 브라우저에서 실행됩니다. 어떤 데이터도 서버로 전송되지 않습니다 — JSON에 API 키, 사용자 기록, 그 외 민감한 정보가 포함될 때 중요합니다.

코드에서 JSON 뷰티파이하기

브라우저 도구가 아니라 프로그램으로 정형 JSON을 만들려면 JSON.stringify의 세 번째 인자가 들여쓰기를 제어합니다:

// 2칸 들여쓰기
JSON.stringify(data, null, 2);

// 4칸 들여쓰기
JSON.stringify(data, null, 4);

// 탭 들여쓰기
JSON.stringify(data, null, '\t');

Python에서는:

import json

# 2칸 들여쓰기, 키 정렬
print(json.dumps(data, indent=2, sort_keys=True))

명령줄에서 jq 사용(기본 출력이 이미 정형됨):

jq . data.min.json

JavaScript에서 JSON 미니파이하기

JavaScript 내장 JSON.stringify는 세 번째 인자(스페이서)를 생략하면 JSON을 미니파이합니다.

JavaScript 객체에서

const data = {
  user: {
    id: 42,
    name: "Alice",
    roles: ["admin", "editor"],
    active: true
  }
};

const minified = JSON.stringify(data);
// {"user":{"id":42,"name":"Alice","roles":["admin","editor"],"active":true}}

라이브러리가 필요 없습니다. JSON.stringify(value)는 항상 압축된 출력을 만듭니다.

JSON 문자열에서(parse 후 다시 stringify)

정형 JSON 문자열에서 출발해 미니파이하려면:

const formatted = `{
  "user": {
    "id": 42,
    "name": "Alice"
  }
}`;

const minified = JSON.stringify(JSON.parse(formatted));
// {"user":{"id":42,"name":"Alice"}}

이 왕복 — parse 후 스페이서 없이 stringify — 가 표준 접근법입니다. 유용한 부수 효과가 있습니다: JSON.parse는 입력이 유효하지 않으면 예외를 던지므로, 전송 시도 전에 잘못된 JSON이 잡힙니다.

Node.js에서 파일 읽기

import { readFileSync, writeFileSync } from 'fs';

const input = readFileSync('data.json', 'utf8');
const minified = JSON.stringify(JSON.parse(input));
writeFileSync('data.min.json', minified);

Python에서 JSON 미니파이하기

Python의 json 모듈은 json.dumps에 두 개의 인자를 줘서 깔끔하게 처리합니다.

Python dict에서

import json

data = {
    "user": {
        "id": 42,
        "name": "Alice",
        "roles": ["admin", "editor"],
        "active": True
    }
}

minified = json.dumps(data, separators=(',', ':'))
# {"user":{"id":42,"name":"Alice","roles":["admin","editor"],"active":true}}

핵심은 separators=(',', ':') 인자입니다. 기본적으로 json.dumps', '': '(후행 공백 포함)을 씁니다. (',', ':')을 넘기면 그 공백을 완전히 제거합니다.

JSON 파일에서

import json

with open('data.json', 'r') as f:
    data = json.load(f)

with open('data.min.json', 'w') as f:
    json.dump(data, f, separators=(',', ':'))

명령줄에서 JSON 미니파이하기

jq 사용

jq는 유닉스 계열 시스템의 표준 JSON 프로세서입니다. -c 플래그가 압축(미니파이) 출력을 만듭니다:

jq -c . data.json > data.min.json

# 인라인
echo '{ "name": "Alice", "age": 30 }' | jq -c .
# {"name":"Alice","age":30}

Python 사용(추가 설치 불필요)

jq가 없다면 Python은 거의 항상 존재합니다:

python3 -m json.tool --compact data.json > data.min.json

--compact 플래그는 Python 3.9에서 추가되었습니다. 이전 버전:

python3 -c "import json,sys; print(json.dumps(json.load(sys.stdin), separators=(',',':')))" < data.json

온라인에서 JSON 미니파이하기

일회성 작업 — 커밋 전 설정 파일, 어디에 복사할 API 응답 — 에는 브라우저 기반 도구가 어떤 CLI 셋업보다 빠릅니다. 좋은 온라인 JSON 미니파이어는 붙여넣기나 파일 업로드를 받고 클라이언트에서 즉시 미니파이하며 데이터를 서버로 보내지 않습니다.

fixjson의 JSON 미니파이어는 모든 처리를 로컬에서 합니다. JSON을 붙여넣고 Minify를 누른 뒤 결과를 복사 — 그 어떤 것도 브라우저를 떠나지 않습니다.

JSON 미니파이로 실제로 얼마나 절약되나

감소 폭은 원래의 정형 방식에 달려 있습니다.

  • 가볍게 정형(2칸 들여쓰기, 얕은 중첩): 보통 15–25% 절약
  • 강하게 정형(4칸 들여쓰기, 깊은 중첩, 키 많음): 보통 30–50% 절약
  • 이미 압축(미니파이됨 또는 기계 생성): 거의 0% 절약

실제 사례 — 100개 사용자 객체 리스트를 반환하는 REST API 응답:

형식크기
정형(2칸)24.8 KB
미니파이16.1 KB
미니파이 + gzip3.2 KB

gzip 행을 보세요. 이 가이드에서 가장 중요한 관찰이며 — 곧 다음 질문으로 이어집니다.

미니파이와 압축: 무엇이 다른가?

미니파이는 공백 문자를 제거합니다 — 데이터 수준에서 무손실이고 더 작은 텍스트 문자열을 만듭니다. 압축(gzip, Brotli, zstd)은 파일 전체에서 반복되는 바이트 패턴을 찾아 더 효율적으로 표현하는 알고리즘을 씁니다. 바이너리 수준에서 동작하며 출력은 먼저 해제하지 않으면 읽을 수 없습니다.

실무적 함의: 서버에서 HTTP 압축이 켜져 있을 때 — 모든 JSON API는 그래야 합니다 — gzip이나 Brotli는 다른 모든 것과 마찬가지로 공백도 적극적으로 압축합니다. 압축 전에 미니파이해도 압축이 이미 달성하는 것 위로는 보통 미미한 추가 감소(3–8%)만 얻습니다.

이는 결정을 다시 짭니다:

  • 서버가 HTTP 압축을 쓰면: 미니파이는 사소한 최적화
  • 디스크나 DB에 JSON을 저장하는데 압축이 없다면: 미니파이는 저장 비용을 의미 있게 줄일 수 있음
  • HTTP 압축을 지원하지 않는 클라이언트에 JSON을 보낸다면: 미니파이는 더 중요

실무의 압축: HTTP/2, HTTP/3, 무엇을 확인해야 하나

최신 HTTP 버전이라고 셈법이 바뀌지는 않습니다 — 압축은 여전히 응답 본문 수준에서 일어납니다 — 다만 미니파이할지 결정할 때 살펴볼 헤더가 몇 개 있습니다:

  • Content-Encoding: gzip(또는 Brotli의 br, 일부 환경에서는 zstd) — 전송 중 본문이 압축되었음을 확인.
  • Vary: Accept-Encoding — CDN이 압축/비압축 응답을 분리해 캐시하기 위해 필요.
  • HTTP/2 / HTTP/3 헤더 압축(HPACK / QPACK) — 본문이 아니라 헤더를 압축. JSON 페이로드의 gzip/brotli를 대체하지 않음.

CDN이 이미 br로 제공한다면 미니파이로 추가로 얻는 것은 몇 퍼센트뿐입니다. 압축하지 않는 서비스(커스텀 바이너리, 웹훅 대상, IoT 엔드포인트)를 다룬다면 미니파이는 여전히 도움이 됩니다.

큰 JSON은 미니파이 대신 스트리밍

정말 큰 페이로드 — 수 MB 규모의 API 응답, 로그 덤프, 데이터셋 익스포트 — 에는 한 덩어리를 미니파이하기보다 스트림하는 것이 옳을 때가 많습니다. 두 가지 패턴:

  • NDJSON / JSON Lines — 한 줄에 JSON 값 하나를 내보냄. 클라이언트는 전체 문서를 기다리지 않고 각 줄이 도착하는 대로 파싱·처리할 수 있다.
  • 청크 스트리밍 파서clarinet / jsonparse 같은 라이브러리는 네트워크에서 도착하는 토큰을 즉시 처리. 메모리 제약 환경에 필요한 동작.

JSON을 미니파이해야 할 때

프로덕션 API 응답(HTTP 압축 없이)

API 서버가 Content-Encoding: gzip이나 Content-Encoding: br를 켜지 않으면 공백 한 바이트까지 전송됩니다. 미니파이는 페이로드 크기를 줄이고 응답을 빠르게 합니다 — 특히 느린 모바일 회선에서.

HTML에 임베드된 JSON

<script type="application/json"> 태그나 HTML에 직접 들어간 JSON은 페이지 전체 무게의 일부입니다. 미니파이하면 초기 페이지 로드를 더 작게 만드는 데 기여합니다.

대규모로 저장되는 JSON 파일

데이터 웨어하우스, 객체 저장소, 데이터베이스에 수백만 건의 JSON 레코드를 저장하고 저장 계층에서 압축하지 않는다면 — 공백이 쌓입니다. 1,000만 건에 걸쳐 30% 절약은 의미가 큽니다.

크기 제한이 있는 엣지 케이스

어떤 시스템에는 단단한 크기 제한이 있습니다: 웹훅 페이로드, 특정 메시지 큐, 쿠키 값, URL 파라미터. JSON이 제한에 가깝다면 미니파이가 그 안에 머물기 위한 가장 단순한 길일 수 있습니다.

빌드 산출물과 번들된 설정

프런트엔드 빌드에 번들되는 JSON 설정 파일은 번들 크기에 기여합니다. JS/CSS처럼 빌드 단계의 일부로 미니파이하는 것이 표준입니다.

굳이 안 해도 될 때

서버가 이미 HTTP 압축을 사용 중

응답 헤더를 확인하세요. Content-Encoding: gzip이나 Content-Encoding: br이 보이면 서버가 이미 전송 중 JSON을 압축하고 있습니다. 그 위에 미니파이를 더해도 이미 압축된 페이로드에서는 기껏해야 몇 퍼센트만 더 — 복잡성에 비해 종종 가치가 없습니다.

JSON이 사람을 위한 것

개발자가 편집하는 설정, 디버그 로그, 사람이 검토할 익스포트 데이터 — 이런 것은 압축보다 가독성이 훨씬 중요합니다. 사람이 자주 읽어야 하는 JSON은 절대 미니파이하지 마세요.

데이터가 이미 작다

1 KB 미만의 JSON 페이로드에서는 미니파이 버전과 정형 버전의 절대 차이가 종종 300바이트 미만입니다. 이 규모에서는 HTTP 요청 자체의 오버헤드가 지배적이며, 본문에서 200바이트를 깎아내봐야 측정 가능한 성능 영향이 없습니다.

디버깅이 어려워진다

로그, 오류 메시지, 모니터링 시스템에 있는 미니파이된 JSON은 훑어보기 힘듭니다. 프로덕션에서 JSON 출력을 읽어야 한다면 정형 상태를 유지하세요.

빌드 파이프라인의 미니파이

JSON 설정 파일을 미니파이하는 Node.js 빌드 파이프라인의 실용적 구성:

// scripts/minify-configs.js
import { readdirSync, readFileSync, writeFileSync } from 'fs';
import { join } from 'path';

const configDir = './config';
const outputDir = './dist/config';

for (const file of readdirSync(configDir)) {
  if (!file.endsWith('.json')) continue;
  const raw = readFileSync(join(configDir, file), 'utf8');
  const minified = JSON.stringify(JSON.parse(raw));
  writeFileSync(join(outputDir, file), minified);
  const saved = raw.length - minified.length;
  console.log(`${file}: ${raw.length} → ${minified.length} bytes (saved ${saved})`);
}

이걸 배포 전 단계로 실행하세요. 설정 파일에 잘못된 JSON이 있으면 JSON.parse가 예외를 던지고 빌드가 실패합니다 — 바로 원하는 동작입니다.

JSON 미니파이 시 흔한 실수

미니파이를 난독화로 여김

미니파이된 JSON은 의미 있는 어떤 수준에서도 숨겨지지 않습니다. 누구나 몇 초 안에 포매터에 돌려 모두 읽을 수 있습니다. 민감한 데이터를 미니파이하고 일이 끝났다고 여기지 마세요 — 적절한 암호화를 쓰거나 민감 데이터 전송 자체를 피하세요.

Python의 인코딩 옵션을 잊음

json.dumps는 기본적으로 ASCII 안전 출력을 만들고 비 ASCII 문자를 \uXXXX로 이스케이프합니다. UTF-8 문자를 그대로 두려면 ensure_ascii=False를 넘기세요:

minified = json.dumps(data, separators=(',', ':'), ensure_ascii=False)

큰 정수에서 정밀도 손실

아주 큰 정수를 가진 JSON을 파싱 후 다시 stringify하면 일부 언어에서 정밀도가 손실될 수 있습니다. JavaScript의 JSON.parse는 모든 숫자를 IEEE 754 double로 변환하므로 2⁵³ 이상의 정수를 정확히 표현할 수 없습니다. JSON에 큰 정수(DB ID 또는 외부 서비스 ID)가 있다면 parse-stringify 왕복이 그것들을 망가뜨리지 않는지 확인하세요.

자주 묻는 질문

JavaScript에서 JSON을 어떻게 미니파이하나요?

세 번째 인자 없이 JSON.stringify(value)를 호출하세요 — 출력은 항상 압축 형태입니다. 기존 문자열을 미니파이하려면 왕복: JSON.stringify(JSON.parse(formatted)).

JSON 미니파이가 파일 크기를 크게 줄이나요?

압축 전 보통 15–50%, 들여쓰기와 중첩에 따라. 하지만 서버가 이미 Content-Encoding: gzip이나 br을 보내면 gzip이 어차피 공백을 압축하므로 먼저 미니파이해 봐야 몇 퍼센트 추가뿐입니다.

JSON 미니파이와 압축은 무엇이 다른가요?

미니파이는 공백을 제거하고 사람이 읽을 수 있는 텍스트를 유지합니다. 압축(gzip, Brotli)은 바이트를 재인코딩하므로 읽으려면 해제가 필요합니다. 둘은 적층 가능하지만 전송 중 작업의 대부분은 압축이 해냅니다.

미니파이와 포매팅은 어떻게 다른가요?

정반대입니다: 미니파이는 크기를 줄이려 공백을 제거하고, 포매팅은 가독성을 위해 공백을 추가합니다. 반대 방향은 JSON 포매팅 방법을 보세요.

결론

JSON 미니파이는 사용 가능한 가장 단순한 최적화 중 하나입니다 — 어느 언어에서나 함수 호출 한 번, 어느 브라우저 도구에서나 한 번의 클릭이면 됩니다. 알맞은 시기는 HTTP 압축 없이 JSON을 전송하거나, 저장 계층의 압축 없이 대규모로 저장하거나, 빌드 산출물에 번들할 때입니다.

잘못된 시기는 JSON이 사람에게 읽힐 의도일 때, 페이로드가 이미 작을 때, 인프라가 이미 전송 중 응답을 압축할 때입니다.

실제로 미니파이해야 한다면 — 빌드 스크립트든 CI 단계든 일회성 정리든 — 방법은 모든 언어에서 동일합니다: JSON을 파싱한 다음 스페이서 없이 직렬화. 파싱을 막는 오류가 있다면 먼저 복구한 뒤 미니파이하세요.