Vercel 무료 플랜에서 OG 이미지 94장 공짜로 만들기 — satori 빌드 타임 생성기
런타임 OG 이미지 생성으로 Vercel 사용량 문제를 겪은 뒤, satori로 로컬에서 한 번만 생성해 PNG를 커밋하는 방식으로 바꿨습니다. 94장을 15초에 만든 실제 구성을 공유합니다.
안녕하세요. Jay입니다!
블로그나 웹 서비스 링크를 카톡·슬랙에 붙였을 때 나오는 미리보기 이미지, OG 이미지 만들고 계신가요? 페이지가 몇 개 없을 땐 디자인 툴로 하나씩 만들면 되지만, 페이지가 수십 개가 되면 얘기가 달라집니다. 저는 운영 중인 사이트의 블로그 글 47편 × 한/영 2개 언어 = 94장이 필요했는데요, 오늘은 이걸 서버 비용 0원으로, 15초 만에 만든 방법을 공유합니다.
💸 먼저, 제가 밟았던 지뢰 — 런타임 생성
Next.js에는 요청이 올 때마다 OG 이미지를 서버에서 그려주는 방법(ImageResponse)이 있습니다. 코드 몇 줄이면 되니 처음엔 이걸 썼는데요, Vercel 무료 플랜에서 사용량 문제를 직접 겪었습니다. 크롤러와 SNS 봇이 링크를 긁을 때마다 이미지 생성 함수가 실행되니, 트래픽도 없는 사이트에서 함수 호출이 무섭게 쌓이더라고요.
그때 정한 원칙이 지금까지 유지되고 있습니다 — OG 이미지는 미리 만들어두고, 서버는 파일만 서빙한다.
🛠 구성 — satori로 로컬에서 한 번만 생성
만드는 도구는 Vercel이 공개한 satori입니다. HTML/CSS 비슷한 구조를 SVG로 그려주는 라이브러리인데, 여기에 resvg-js로 SVG→PNG 변환을 붙이면 끝입니다. 제 스크립트의 동작은 이렇습니다.
- 로컬에서 개발 서버를 켠다
- 스크립트가 각 페이지를 방문해
og:title과og:description메타태그를 읽어온다 — 제목을 따로 관리하지 않으니 페이지와 이미지가 어긋날 일이 없습니다 - satori로 1200×630 카드를 그린다 (한글은 Noto Sans KR woff를 폰트로 주입)
- PNG로 저장 → git에 커밋 → 배포하면 Vercel은 정적 파일만 서빙
핵심은 4번입니다. 생성은 제 맥에서 한 번, 서버에서는 함수 호출 0회. 이미지가 바뀔 일이 생기면 로컬에서 다시 돌려 커밋하면 됩니다.
⚙️ 운영하며 다듬은 디테일 3가지
① 페이지 목록 자동 등재 — 처음엔 라우트 목록을 스크립트에 손으로 적었는데, 블로그 글이 늘 때마다 까먹기 딱 좋습니다. 그래서 글 목록 데이터 파일을 정규식으로 파싱해 /blog/* 라우트를 자동으로 등재하게 바꿨어요. 이제 새 글을 쓰면 생성 대상에 자동 포함됩니다.
② --only= 부분 재생성 필터 — 94장 전체를 매번 다시 그릴 필요는 없죠. --only=/blog/처럼 경로 앞부분으로 필터링해 바뀐 구역만 재생성합니다.
③ 카테고리별 색상 — 페이지 성격(금융·건강·게임·블로그…)에 따라 카드의 포인트 색을 다르게 줬습니다. 단조로운 대량 생성 티를 지우는 작은 장치예요.
실제 실행 결과는 이랬습니다 — 94장 생성, 실패 0, 약 15초. 한 장씩 디자인 툴로 만들었으면 하루가 갔을 겁니다.
🤔 이 방식이 안 맞는 경우
공정하게 한계도 적어둡니다. 사용자 입력에 따라 이미지가 달라져야 하는 경우(예: 동적 프로필 카드)는 런타임 생성이 필요합니다. 제 방식은 "페이지가 정해져 있고 내용이 자주 안 바뀌는" 블로그·도구 사이트에 딱 맞는 방식이에요. 그리고 PNG를 git에 커밋하니 저장소가 무거워지는 트레이드오프가 있습니다 (94장에 약 20MB 수준 — 저는 감수할 만했습니다).
결론
OG 이미지는 요청마다 그리지 말고, 로컬에서 한 번 그려 커밋하세요. Vercel 무료 플랜이 평온해집니다.
무료 플랜으로 사이드 프로젝트를 굴리는 분들께 특히 권합니다. 함수 사용량 그래프에서 OG 생성이 사라지는 걸 보면 꽤 개운하거든요. 다음에도 유익한 포스팅으로 찾아오겠습니다. 감사합니다!