treeru.com
개발

sharp 이미지 최적화 — 명령 하나로 웹 이미지 압축 자동화

2026-01-15
Treeru

웹사이트가 느리다면 이미지부터 의심해야 합니다. Photoshop을 열 필요 없이, sharp 라이브러리 하나면 터미널에서 이미지 최적화를 자동으로 처리할 수 있습니다. WebP/AVIF 변환, 리사이즈, 배치 처리까지 명령어 하나로 끝내는 방법을 정리했습니다.

~90%

파일 크기 감소

200장

30초 배치 처리

WebP

주력 포맷

AVIF

차세대 포맷

1sharp 라이브러리 소개

sharp는 Node.js 환경의 고성능 이미지 처리 라이브러리입니다. 내부적으로 libvips를 사용하기 때문에 ImageMagick보다 4~5배 빠릅니다. Next.js의 이미지 최적화에도 sharp가 사용됩니다.

# 설치

npm install sharp

# 또는
yarn add sharp
pnpm add sharp

sharp의 주요 특징

libvips 기반 고성능 처리 (ImageMagick 대비 4~5배 빠름)
WebP, AVIF, PNG, JPEG, TIFF 포맷 지원
리사이즈, 크롭, 회전, 블러 등 다양한 변환
스트리밍 API로 대용량 이미지도 메모리 효율적 처리
Promise/async-await 지원
Next.js 공식 이미지 최적화 엔진

2WebP vs AVIF 비교

두 포맷 모두 JPEG보다 압축률이 좋지만, 특성이 다릅니다. 어떤 포맷을 선택할지 비교해봤습니다.

항목WebPAVIFJPEG
압축률 (동일 품질)25~35% 절감40~50% 절감기준
인코딩 속도빠름느림 (5~10배)매우 빠름
브라우저 지원97%+92%+100%
투명도 지원지원지원미지원
애니메이션지원지원미지원
권장 용도범용 (현시점 최적)정적 이미지 고압축폴백용

현실적 선택

WebP를 메인으로 쓰고, AVIF는 점진적으로 도입하는 것을 권장합니다. AVIF가 압축률은 더 좋지만, 인코딩 시간이 오래 걸리고 아직 Safari 구버전에서 지원이 불완전합니다. 빌드 시간이 중요한 프로젝트라면 WebP만으로도 충분합니다.

3압축 스크립트 작성

기본적인 이미지 변환 스크립트부터 시작합니다. 하나의 이미지를 WebP와 AVIF 두 포맷으로 동시에 변환하는 코드입니다.

# optimize.mjs - 기본 변환 스크립트

import sharp from 'sharp';
import path from 'path';

async function optimizeImage(inputPath) {
  const dir = path.dirname(inputPath);
  const name = path.basename(inputPath, path.extname(inputPath));

  // WebP 변환 (품질 80, 리사이즈 1920px)
  await sharp(inputPath)
    .resize({ width: 1920, withoutEnlargement: true })
    .webp({ quality: 80 })
    .toFile(path.join(dir, `${name}.webp`));

  // AVIF 변환 (품질 65, 더 높은 압축률)
  await sharp(inputPath)
    .resize({ width: 1920, withoutEnlargement: true })
    .avif({ quality: 65 })
    .toFile(path.join(dir, `${name}.avif`));

  console.log(`완료: ${name}`);
}

// 사용: node optimize.mjs ./images/photo.jpg
optimizeImage(process.argv[2]);

# 실행 결과 예시

$ node optimize.mjs ./public/images/hero.jpg

원본:    hero.jpg      2.4 MB
WebP:    hero.webp     320 KB  (87% 감소)
AVIF:    hero.avif     210 KB  (91% 감소)

withoutEnlargement 옵션은 필수입니다

원본보다 작은 이미지를 리사이즈할 때 강제로 키우는 걸 방지합니다. 800px짜리 아이콘을 1920px로 늘리면 용량만 커지고 품질은 떨어지니까요.

4배치 처리 자동화

이미지가 한두 장이면 수동으로 해도 되지만, 수십~수백 장이면 자동화가 필수입니다. 폴더 안의 모든 이미지를 한번에 처리하는 스크립트입니다.

# batch-optimize.mjs - 폴더 전체 배치 처리

import sharp from 'sharp';
import fs from 'fs';
import path from 'path';

const SUPPORTED = ['.jpg', '.jpeg', '.png', '.tiff'];

async function batchOptimize(inputDir, outputDir) {
  const files = fs.readdirSync(inputDir)
    .filter(f => SUPPORTED.includes(
      path.extname(f).toLowerCase()
    ));

  console.log(`${files.length}개 파일 처리 시작...`);
  fs.mkdirSync(outputDir, { recursive: true });

  let totalSaved = 0;
  for (const file of files) {
    const inputPath = path.join(inputDir, file);
    const name = path.basename(file, path.extname(file));
    const originalSize = fs.statSync(inputPath).size;

    await sharp(inputPath)
      .resize({ width: 1920, withoutEnlargement: true })
      .webp({ quality: 80 })
      .toFile(path.join(outputDir, `${name}.webp`));

    const newSize = fs.statSync(
      path.join(outputDir, `${name}.webp`)
    ).size;
    const saved = originalSize - newSize;
    totalSaved += saved;

    console.log(
      `  ${file} → ${name}.webp `
      + `(${(saved/1024).toFixed(0)}KB 절감)`
    );
  }

  console.log(
    `\n총 ${(totalSaved/1024/1024).toFixed(1)}MB 절감`
  );
}

batchOptimize('./public/images', './public/images/optimized');

처리 속도

200장/30초

1920px WebP 기준

평균 압축률

85~90%

JPEG → WebP 기준

메모리 사용

~100MB

순차 처리 시

5품질 튜닝 가이드

이미지 용도에 따라 최적의 품질 설정이 다릅니다. 무조건 낮추면 용량은 줄지만 화질이 깨지고, 너무 높으면 압축 효과가 없습니다.

이미지 용도WebP 품질AVIF 품질최대 너비
히어로 배경85701920px
블로그 썸네일8065800px
카드 이미지7560600px
아이콘/로고9080원본 유지
갤러리/포트폴리오85701440px
OG 이미지80651200px

# 용도별 설정 적용 예시

const profiles = {
  hero:      { width: 1920, webpQ: 85, avifQ: 70 },
  thumbnail: { width: 800,  webpQ: 80, avifQ: 65 },
  card:      { width: 600,  webpQ: 75, avifQ: 60 },
  icon:      { width: null, webpQ: 90, avifQ: 80 },
};

async function optimize(input, profile = 'thumbnail') {
  const { width, webpQ, avifQ } = profiles[profile];
  const pipeline = sharp(input);

  if (width) pipeline.resize({ width, withoutEnlargement: true });

  await pipeline.clone().webp({ quality: webpQ })
    .toFile(input.replace(/\.[^.]+$/, '.webp'));
  await pipeline.clone().avif({ quality: avifQ })
    .toFile(input.replace(/\.[^.]+$/, '.avif'));
}

튜닝 팁

품질 70 이하로 내리면 텍스트가 포함된 이미지에서 뭉개짐이 눈에 띄기 시작합니다. 사진 위주라면 60까지도 괜찮지만, 스크린샷이나 다이어그램은 80 이상을 유지하세요.

6빌드 파이프라인 통합

수동으로 스크립트를 돌리는 건 결국 까먹게 됩니다. 빌드 과정에 넣어서 자동으로 실행되게 만드는 게 좋습니다.

# package.json에 스크립트 추가

{
  "scripts": {
    "optimize:images": "node scripts/batch-optimize.mjs",
    "prebuild": "npm run optimize:images",
    "build": "next build"
  }
}

통합 시 고려사항

이미 최적화된 이미지는 건너뛰도록 캐시 로직 추가
원본 이미지는 별도 폴더에 보관 (덮어쓰기 방지)
CI/CD 환경에서 sharp 네이티브 모듈 호환성 확인
.gitignore에 최적화된 이미지 폴더 추가 여부 결정
빌드 시간 증가 모니터링 (AVIF 인코딩은 느림)

Next.js와 함께 사용할 때

Next.js의 <Image> 컴포넌트는 자체적으로 이미지 최적화를 하지만, 빌드 타임에 미리 최적화해두면 런타임 부하를 줄이고 초기 로딩 속도를 개선할 수 있습니다. 특히 정적 생성(SSG) 사이트에서 효과가 큽니다.

이 글의 핵심 정리

  • sharp는 Node.js 최고 성능의 이미지 처리 라이브러리 — ImageMagick보다 4~5배 빠름
  • WebP를 메인으로, AVIF는 점진 도입 권장 — 브라우저 호환성과 인코딩 속도 고려
  • 배치 처리로 200장 이미지를 30초에 처리 가능 — 수동 작업 대비 압도적 효율
  • 용도별 품질 튜닝 필수 — 히어로 85, 썸네일 80, 카드 75가 기본 설정
  • 빌드 파이프라인에 통합하면 최적화를 까먹을 일이 없음

본 글은 2026년 2월 기준 sharp 0.33.x 버전을 기반으로 작성되었습니다. 라이브러리 버전에 따라 API가 달라질 수 있으며, 브라우저 포맷 지원률은 지속적으로 변합니다. 이미지 품질 설정은 이미지 특성에 따라 달라지므로, 실제 적용 전 시각적 품질을 확인하세요. 본 콘텐츠의 비상업적 공유는 자유이나, 상업적 이용 시 문의 페이지를 통해 연락 바랍니다.

웹사이트 성능 최적화가 필요하신가요?

Treeru가 이미지 최적화부터 PageSpeed 개선까지 통합 최적화 서비스를 제공합니다.

무료 상담 신청하기
T

Treeru

웹 개발, IT 인프라, AI 솔루션 분야의 실무 인사이트를 공유합니다. 기업의 디지털 전환을 돕는 IT 파트너, Treeru입니다.

공유

댓글

(4개)
4.50/ 5

로그인하면 댓글을 작성할 수 있습니다.

2026-01-27
555.0

WebP vs AVIF 비교표가 깔끔합니다. 아직 Safari 구버전 호환성 때문에 WebP를 메인으로 쓰고 AVIF는 점진 도입 중입니다.

2026-01-23
4.554.5

빌드 파이프라인에 통합하는 방법이 실용적입니다. CI/CD에서 이미지 최적화를 자동으로 돌리면 배포 사이즈가 확 줄어듭니다.

2026-01-20
454.0

블로그 이미지가 30장 넘어가니까 수동 최적화는 불가능했는데, 배치 처리 스크립트 덕분에 한방에 해결했습니다.

관련 글

© 2026 TreeRU. All rights reserved.

본 콘텐츠의 저작권은 TreeRU에 있으며, 출처를 밝히지 않은 무단 전재 및 재배포를 금합니다. 인용 시 출처(treeru.com)를 반드시 명시해 주세요.