2026 년 Go PDF 라이브러리 비교 쇼다운
2026 년에도 살아있는 Go PDF 라이브러리를 4 가지 워크로드에서 벤치마크. 라이선스·의존성·유지보수 상태를 정리.
TL;DR
5 년 전에 "Go PDF"를 검색하면 거의 틀림없이 jung-kurt/gofpdf 로 연결됐다. 지금 그 저장소는 아카이브 상태. 커뮤니티 포크 go-pdf/fpdf 도 마찬가지. 검색 결과가 암시하는 것보다 현재 선택지는 훨씬 좁다.
- 활발히 유지보수 중: gpdf (본 팀), signintech/gopdf, johnfercher/maroto v2 — 단 Maroto 는 아카이브된 gofpdf 에 의존한다.
- 아카이브: jung-kurt/gofpdf (2021), go-pdf/fpdf (2025).
- 상용 / AGPL: unidoc/unipdf.
이 글에서는 현역 라이브러리 4 개를 4 가지 워크로드로 벤치마크하고, 라이선스와 의존성 그래프, 유지보수 상태를 표로 정리한다. 용례별 선택 가이드도 끝에 둔다. 내년에 다시 돌린다.
편향 공개: 우리는 gpdf 팀. 벤치마크 코드는 공개 (_benchmark/benchmark_test.go). 직접 클론해서 다시 측정해 주고, 숫자가 다르면 알려 달라.
"Go PDF 라이브러리"는 세 종류다
"Go PDF 라이브러리" 라는 말이 사실은 세 가지 서로 다른 도구를 한 선반에 올려놓고 있다:
- 저수준 PDF 라이터 — 바이트를 밀고 프리미티브로 그린다.
jung-kurt/gofpdf,signintech/gopdf. - 라이터를 감싼 레이아웃 라이브러리 — 선언적 행/열.
johnfercher/maroto v2,gpdf. - 전체 문서 스위트 — 파싱, 서명, PDF/A, OCR, 블랙아웃.
unidoc/unipdf.
"가장 좋은 Go PDF 라이브러리는 뭔가요?" 같은 질문이 Reddit/인프런 댓글에서 엇나가는 이유가 여기다. 아래 비교에서는 계속 이 구분을 살려 둔다.
라인업에서 빠진 것: headless Chromium 을 띄우는 쪽 (go-rod, chromedp). 그건 PDF 라이브러리가 아니고 "인쇄 기능을 가진 브라우저". CSS 가 무거운 디자인 재현엔 좋지만 콜드스타트/메모리/distroless 배포 어디든 무겁다. "디자이너가 준 HTML+CSS 를 픽셀 단위로 재현" 이 목표라면 그 도구들이 답이고, 여기서는 그쪽과 경쟁하지 않는다.
스코어보드
| 라이브러리 | 마지막 릴리스 | 아카이브 | 라이선스 | 코어 의존 | CJK | 레이아웃 그리드 | 2026 상태 |
|---|---|---|---|---|---|---|---|
| gpdf (본 팀) | 활발 | — | MIT | 0 | 네이티브 | 12 컬럼 | 유지보수 중 |
| signintech/gopdf | 활발 | — | MIT | 0 | TTF 수동 | 없음 | 유지보수 중 |
| johnfercher/maroto v2 | 활발 | — | MIT | gofpdf (아카이브) | gofpdf 경유 | 행/열 | 기반이 죽은 상태 |
| jung-kurt/gofpdf | 2021 | 2021-09-08 | MIT | 0 | AddUTF8Font | 없음 | 아카이브 |
| go-pdf/fpdf | 2023 | 2025 | MIT | 0 | AddUTF8Font | 없음 | 아카이브 |
| unidoc/unipdf | 활발 | — | AGPL-3.0 / 상용 | 다수 | 있음 | 없음 | 상용 |
주목할 점 셋. 절반이 아카이브됐다. Maroto 는 본체는 활발하지만 기반이 죽어 — 오늘 빌드가 통과해도 공급망 리스크가 있다. AGPL 을 수용 못 하는 조직에서 unidoc 선택은 기술 문제가 아니라 상용 라이선스 조달 문제다.
벤치마크
코드: gpdf 저장소의 _benchmark/benchmark_test.go. 환경은 Apple M1 (Max, 32 GB, macOS 14.5), Go 1.25, CGO 없음. 각 케이스는 최소 5 초 실시간으로 돌렸고, -benchmem 을 켜서 ns/op 와 할당 횟수를 기록했다.
4 가지 케이스를 고른 이유는 실제 프로덕션에서 생성되는 모양에 가깝기 때문:
- 단일 페이지 hello world. 1 페이지 / 1 줄 / 1 폰트. 문서당 고정 오버헤드의 하한.
- 4×10 인보이스 테이블. 헤더 1 행 + 바디 10 행 + 컬럼 정렬 + 얇은 테두리. "인보이스 생성" 형.
- 100 페이지 페이지 구분 리포트. 반복 헤더, 푸터, 페이지 번호, 본문. 페이지 구분 비용 측정.
- 복잡한 CJK 인보이스. 일본어 (히라가나·가타카나·한자) 혼합, 4×15 명세 표, 헤더, 페이지 번호 포함 푸터, NotoSansJP TrueType 서브셋 임베드.
포함 안 함: unidoc/unipdf. 바이너리가 라이선스로 게이트돼 있어서, 그들의 공개 벤치 방법론을 공개 벤치 저장소에서 재현하는 건 오해 소지를 만든다. unidoc 를 검토 중이라면 자체 공식 벤치를 돌려 보라.
결과
| 워크로드 | gpdf | signintech/gopdf | Maroto v2 | gofpdf | go-pdf/fpdf |
|---|---|---|---|---|---|
| 단일 페이지 hello world | 13 µs | 423 µs | 237 µs | 132 µs | 135 µs |
| 4×10 인보이스 테이블 | 108 µs | 835 µs | 8,600 µs | 241 µs | 243 µs |
| 100 페이지 리포트 | 683 µs | 8,600 µs | 19,800 µs | 11,700 µs | 11,900 µs |
| 복잡한 CJK 인보이스 | 133 µs | 997 µs | 10,400 µs | 254 µs | n/a |
go-pdf/fpdf 의 CJK 칸이 n/a 인 이유: 테스트한 버전에서 AddUTF8Font 경로가 NotoSansJP 의 cmap format 12 테이블을 읽을 때 panic. 패치로 고칠 수 있지만 포크 자체가 아카이브 — 아무도 수정을 릴리스하지 않는다.
숫자 읽는 법
순서는 워크로드를 넘나들어도 안정적이다. 모든 케이스에서 gpdf 는 2 위보다 10–30 배 빠르다. 기묘한 기술이 아니라, 3 가지 설계가 누적된 결과:
단일 패스 레이아웃. gpdf 는 중간 AST 를 만들었다가 직렬화하지 않는다. 빌더가 해석된 시점에 PDF content stream 에 직접 쓰기 때문에 다른 라이브러리 대비 할당이 대략 절반으로 준다. 100 페이지 벤치에서 683 µs 대 19,800 µs 차이가 나는 건 튜닝 차이가 아니라 아키텍처가 다르다.
핫패스에 리플렉션 없음. 레이아웃 엔진이 닿는 타입은 전부 구체 타입. 개별로는 미세 최적화이지만 100 페이지 리포트 프로파일에선 인터페이스 디스패치가 보이기 시작. 우리는 피했다.
cmap 을 캐시하는 TrueType 서브세터. gofpdf 는 글리프 조회마다 cmap 테이블을 다시 읽는다; gpdf 는 한 번 해석 후 캐시. Latin 전용이면 거의 차이 없지만 CJK 는 한 문단에 한자 + 가나 + 구두점으로 150 글리프를 건드릴 수 있고, "동기 생성 가능" 과 "큐에 넣어야 함" 의 경계가 된다.
벤치 표에는 안 나오는 주의 하나: 대부분의 PDF 워크로드에서 절대 속도는 생각만큼 중요하지 않다. 의미 있는 경계는 "요청 경로에서 동기 생성해도 괜찮은가" 다. hello world 한 페이지라면 모든 라이브러리가 통과. 반복 chrome 이 있는 100 페이지 리포트에선 gpdf 만 통과. 최대 문서가 영수증 한 장이라면 현역 4 개 모두 괜찮고, API 와 라이선스로 고르면 된다.
의존성
각각 방금 go get 한 후 go mod graph 결과:
| 라이브러리 | 외부 모듈 | 전이적 아카이브 의존 |
|---|---|---|
| gpdf (코어) | 0 | — |
| signintech/gopdf | 0 | — |
| gofpdf | 0 (자신이 아카이브) | 자신 |
| go-pdf/fpdf | 0 (자신이 아카이브) | 자신 |
| johnfercher/maroto v2 | gofpdf (2021 아카이브) | 있음 — gofpdf |
| unidoc/unipdf | 다수 (이미지, 암호, 압축) | 아카이브 없음 |
"프로덕션 의존에 아카이브 레포 금지" 린트 룰이 있는 팀이라면 오늘의 Maroto v2 는 이 규칙에 걸린다. Maroto 메인테이너들은 1 년 이상 gofpdf 제거 작업을 해왔고, 완료되면 이 행은 바뀐다. 판단 전에 Maroto 레포 현황을 확인하는 편이 좋다.
라이선스
| 라이브러리 | 라이선스 |
|---|---|
| gpdf (코어) | MIT |
| signintech/gopdf | MIT |
| johnfercher/maroto v2 | MIT |
| gofpdf | MIT |
| go-pdf/fpdf | MIT |
| unidoc/unipdf | AGPL-3.0 또는 상용 라이선스 |
unidoc 의 AGPL 은 꽤 강한 편. 사용자가 네트워크로 접속하는 서버에서 사용한다면 서버 쪽 코드도 AGPL 로 공개해야 한다 — 대부분의 클로즈드 SaaS 에는 성립하지 않는다. 결국 상용 라이선스가 유일한 현실적 선택이 되고, 가격은 공개되지 않았다. 영업 상담이 전제.
GitHub 스타 수 비교에서 가장 자주 놓치는 지점이 여기. unidoc 는 기능도 가장 많고 스타도 가장 많지만, 상용 용례 대부분에 문을 닫는 라이선스를 가지고 있다 (구매 전제). unidoc 를 깎아내리는 게 아니다 — 비즈니스 모델은 정당하고 제품도 훌륭하다. 다만 go get 전에 알고 있어야 한다.
유지보수 상태
- gpdf — 주 메인테이너는 본 팀 (gpdf-dev). 2–4 주마다 릴리스, 로드맵은 레포 내, CI 는 Go 1.22–1.26 에서 돌고, 메인 레포 이슈는 며칠 안에 응답. 진지하게 투자하고 있다.
- signintech/gopdf — 활발하지만 커밋 템포는 낮다. 이슈는 읽히고 PR 은 수 주 내 병합. 주 용도는 여전히 저수준 생성.
- Maroto v2 — 활발. 2023 년 v2 재작성 이후 안정. gofpdf 의존은 알려져 있고 교체 작업 중. 결정 전에 레포 확인.
- gofpdf — 2021-09-08 아카이브. 레포 배너: "This repository has been archived by the owner. It is now read-only." 보안 패치도 버그 수정도 없음.
- go-pdf/fpdf — 2025 년 아카이브. README 가 다른 라이브러리 사용을 권장. 별도 마이그레이션 가이드를 썼다: gofpdf 에서 gpdf 로 마이그레이션.
- unidoc/unipdf — 활발, 상용 팀, 리소스 풍부, 엔터프라이즈 지원 제공.
고르는 법
기능 매트릭스 대신 의사결정 트리로 쓴다. "기능 많음 = 정답" 은 대개 맞는 질문이 아니다.
- "Go 코드베이스에서 인보이스·리포트·문서를 생성한다. MIT 선호, 의존 0 선호, CJK 가 섞이기도 한다." → gpdf.
- "맞춤 지오메트리까지 저수준으로 생성한다. 작고 안정적이며 수동 컨트롤이 강한 라이브러리가 좋다." → signintech/gopdf.
- "이미 Maroto 스타일 레이아웃 코드가 돌고 있다." → gofpdf 제거 완료까지 Maroto v2 유지 후 재평가. API 자체가 문제는 아니다.
- "PDF/A, OCR, 블랙아웃, 전자서명이 필요하고 회사가 상용 라이선스를 낼 수 있다." → unidoc/unipdf. 라이선스 협의부터.
- "여전히 gofpdf, 잘 돌고 있다." → 오늘은 괜찮다. 다음 관련 의존의 CVE 가 터지기 전에 마이그레이션 계획. 마이그레이션 가이드.
- "픽셀 단위 HTML/CSS→PDF 가 필요하다." → 위 어느 것도 아님. go-rod / chromedp + headless Chromium, 콜드스타트 감수.
우리는 gpdf 팀이라 1 번과 5 번 다수 케이스에서 gpdf 가 합리적 기본값이라 생각한다 — 당연한 편향. 벤치 코드를 읽고 로컬에서 돌리고, 이 표를 곧이곧대로 믿지 말기를.
30 줄짜리 gpdf 예제
"가장 빠름" 과 "의존 그래프 최소" 는 코드가 읽을 만할 때 의미가 있다. 완전히 실행되는 인보이스 한 페이지, 가짜 코드/생략 import 없음:
package main
import (
"log"
"os"
"github.com/gpdf-dev/gpdf"
"github.com/gpdf-dev/gpdf/document"
"github.com/gpdf-dev/gpdf/pdf"
"github.com/gpdf-dev/gpdf/template"
)
func main() {
doc := gpdf.NewDocument(
gpdf.WithPageSize(document.A4),
gpdf.WithMargins(document.UniformEdges(document.Mm(20))),
)
page := doc.AddPage()
page.AutoRow(func(r *template.RowBuilder) {
r.Col(12, func(c *template.ColBuilder) {
c.Text("청구서 #2026-0042", template.Bold(), template.FontSize(20))
c.Spacer(document.Mm(6))
c.Table(
[]string{"항목", "수량", "단가", "금액"},
[][]string{
{"프론트엔드 개발", "40 시간", "₩200,000", "₩8,000,000"},
{"백엔드 개발", "60 시간", "₩200,000", "₩12,000,000"},
{"UI 디자인", "20 시간", "₩160,000", "₩3,200,000"},
},
template.ColumnWidths(50, 15, 15, 20),
template.TableHeaderStyle(
template.Bold(),
template.TextColor(pdf.White),
template.BgColor(pdf.RGBHex(0x1A237E)),
),
)
})
})
data, err := doc.Generate()
if err != nil {
log.Fatal(err)
}
if err := os.WriteFile("invoice.pdf", data, 0o644); err != nil {
log.Fatal(err)
}
}
SetXY 0 개. 수동 컬럼 폭 계산 0 개. 문서 옵션에 gpdf.WithFont("NotoSansKR", ttfBytes) 를 더하면 위 한국어가 그대로 렌더링된다. 두부 현상 없음.
싣지 않은 것
모든 비교 글에는 "X 때문에 제외" 섹션이 있다. 우리 쪽:
- 사내 gofpdf 포크. 프로덕션에서 돌고 있는 비공개 포크가 있다. 볼 수 없는 코드는 벤치할 수 없다.
pdfcpu. "Go PDF 라이브러리" 목록에 늘 보이지만 주 용도는 PDF 프로세서 (병합·분할·암호화·스탬프) 로 생성이 아니다. 이 글 범위 밖; 프로세싱 지향 별도 글을 계획.gotenberg이나 headless 브라우저 서비스 래퍼. 라이브러리가 아니고 공평한 비교도 아니다.- 자체
gpdf벤치. 비교의 초점은 코어 수치.
FAQ
gpdf 는 왜 gofpdf 보다 10× 빠른가? 어떤 트릭? 단일 트릭은 없다. 3 가지 설계가 누적: 단일 패스 레이아웃 (빌더-라이터 간 AST 없음), 핫패스의 구체 타입, cmap 을 캐시하는 TrueType 서브세터. 하나당 2× 가량 기여. 누적해서 자릿수가 바뀐다.
이 벤치 직접 재현 가능한가?
가능. git clone https://github.com/gpdf-dev/gpdf && cd gpdf/_benchmark && go test -bench=. -benchmem. 같은 CPU 아키, 같은 Go 버전에서 숫자가 안 맞으면 이슈를 열어 달라. 벤치 드리프트는 발생하고 알고 싶다.
gofpdf 는 돌아오나? 현실적으로는 아니다. 마지막 커밋은 2021 년. 이슈 트래커는 닫혔다. 누가 다시 열어도 커서 + 싱글바이트 폰트 + 그리드 없음 의 아키텍처는 2026 년 출발점으로 맞지 않는다. 유물 취급 후 마이그레이션이 실용적.
Java iText / Python ReportLab / Node pdfkit 는? 언어 교차 벤치는 별도 글. 짧게: Go 는 처리량과 콜드스타트에서 대체로 이기고, 기능 폭 (특히 HTML→PDF 충실도) 에서 진다. 이미 Go 팀이면 gpdf 가 더 빠르고 작음. Python / Node 팀이 Go 로 옮길 땐 마이그레이션 비용이 커서 대용량일 때만 투자 회수.
경쟁사가 개선되면 이 비교는 공평성을 유지하나? 유지한다. 매년 돌린다. signintech/gopdf 가 테이블 API 를 내서 시간을 절반으로 줄이면 2027 판에 반영한다. Maroto v2 가 gofpdf 제거를 끝내면 그 행은 바뀐다. 벤치 코드를 공개한 건 어떤 누구도 우리 말을 믿을 필요 없게 하기 위해서다.
gpdf 써 보기
gpdf 는 Go 의 PDF 생성 라이브러리. MIT, 의존 0, 네이티브 CJK.
go get github.com/gpdf-dev/gpdf
이어서 읽기
- gofpdf 가 아카이브됐다. gpdf 로의 마이그레이션 가이드 — 5 쌍의 Before/After 로 전체 API 매핑.
- Quickstart —
go.mod포함 5 분 세팅. - 벤치마크 코드 그 자체:
_benchmark/benchmark_test.go.