Comparativa de bibliotecas Go PDF 2026
Todas las bibliotecas Go PDF que siguen vivas en 2026, comparadas en 4 cargas de trabajo, con licencias, dependencias y estado de mantenimiento.
TL;DR
Hace cinco años, buscar "biblioteca Go PDF" te llevaba casi siempre a jung-kurt/gofpdf. Hoy está archivado. Su fork comunitario también. El terreno real es bastante más pequeño de lo que sugieren los resultados de búsqueda:
- Mantenidas activamente: gpdf (este equipo), signintech/gopdf, johnfercher/maroto v2 — aunque Maroto sigue dependiendo de un gofpdf archivado.
- Archivadas: jung-kurt/gofpdf (2021), go-pdf/fpdf (2025).
- Comercial / AGPL: unidoc/unipdf.
Este artículo somete a las bibliotecas mantenidas a cuatro cargas de trabajo, expone licencias y grafos de dependencias, y hace una recomendación por caso de uso. Lo volvemos a correr el próximo año.
Declaración de sesgo: somos el equipo de gpdf. El código de los benchmarks es público (_benchmark/benchmark_test.go) — clónalo, relanza los números y cuéntanos dónde nos equivocamos.
Qué estamos comparando realmente
La frase "biblioteca Go PDF" cubre al menos tres herramientas distintas que se hacen pasar por la misma categoría:
- Escritores PDF de bajo nivel — empujas bytes y dibujas con primitivas.
jung-kurt/gofpdf,signintech/gopdf. - Bibliotecas de layout que envuelven un escritor — filas y columnas declarativas por encima.
johnfercher/maroto v2,gpdf. - Suites documentales completas — parseo, firma, PDF/A, OCR, redacción.
unidoc/unipdf.
Pedir "la mejor biblioteca Go PDF" sin decir qué categoría necesitas es la razón por la que la mayoría de los hilos de recomendación en Reddit acaban descarrilando. En cada comparación intentamos mantener esta distinción visible.
Fuera de lista: cualquier cosa que lance un Chromium headless (go-rod, chromedp). Eso no es una biblioteca PDF; es un navegador que imprime. Bueno para fidelidad en CSS complejo, malo para arranque en frío, malo para memoria, malo para distroless. Si tu requisito es "el diseñador me da HTML+CSS y quiere impresión pixel-perfect", esas herramientas existen y no vamos contra ellas en este post.
Marcador
| Biblioteca | Último lanzamiento | Archivada | Licencia | Deps. de núcleo | CJK | Grid de layout | Estado 2026 |
|---|---|---|---|---|---|---|---|
| gpdf (este equipo) | activa | — | MIT | 0 | nativo | 12 columnas | mantenida |
| signintech/gopdf | activa | — | MIT | 0 | TTF manual | no | mantenida |
| johnfercher/maroto v2 | activa | — | MIT | gofpdf (archivada) | vía gofpdf | row/col | mantenida sobre base muerta |
| jung-kurt/gofpdf | 2021 | 2021-09-08 | MIT | 0 | AddUTF8Font | no | archivada |
| go-pdf/fpdf | 2023 | 2025 | MIT | 0 | AddUTF8Font | no | archivada |
| unidoc/unipdf | activa | — | AGPL-3.0 / comercial | muchas | sí | no | comercial |
Tres cosas a notar. Uno: la mitad del campo está archivado. Dos: Maroto está mantenida, pero su cimiento no — es un problema de cadena de suministro aunque compile hoy. Tres: si no puedes aceptar la AGPL, unidoc se vuelve una decisión de licencia comercial, no técnica.
El benchmark
Código: _benchmark/benchmark_test.go en el repo de gpdf. Entorno: Apple M1 (Max, 32 GB, macOS 14.5), Go 1.25, sin CGO. Cada caso corre al menos cinco segundos de tiempo real. -benchmem activado; reportamos ns/op y asignaciones.
Elegimos estos cuatro casos porque reflejan lo que la gente genera de verdad, no algo microsintético:
- Hello world de una página. Una página, una línea de texto, una fuente. Marca el suelo de sobrecoste por documento.
- Tabla de factura 4×10. Una fila de cabecera, diez filas de cuerpo, alineaciones de columna, bordes finos. La forma "generar mi factura".
- Reporte paginado de 100 páginas. Cabecera repetida, pie, números de página, cuerpo en cada página. Mide el coste de paginación.
- Factura CJK compleja. Japonés mixto (Hiragana, Katakana, Kanji), tabla de ítems 4×15, cabecera, pie con número de página, subconjunto TrueType NotoSansJP embebido.
No incluido: unidoc/unipdf. Su binario está protegido por licencia, y reproducir su metodología de benchmark publicada dentro de un repo público confundiría más que aclararía. Si estás evaluando unidoc, corre sus propios benchmarks — los publican.
Resultados
| Carga de trabajo | gpdf | signintech/gopdf | Maroto v2 | gofpdf | go-pdf/fpdf |
|---|---|---|---|---|---|
| Hello world de una página | 13 µs | 423 µs | 237 µs | 132 µs | 135 µs |
| Tabla de factura 4×10 | 108 µs | 835 µs | 8,600 µs | 241 µs | 243 µs |
| Reporte paginado de 100 págs. | 683 µs | 8,600 µs | 19,800 µs | 11,700 µs | 11,900 µs |
| Factura CJK compleja | 133 µs | 997 µs | 10,400 µs | 254 µs | n/d |
n/d para go-pdf/fpdf en el caso CJK: la ruta por defecto de AddUTF8Font entra en panic al leer la tabla cmap formato 12 de NotoSansJP en la versión probada. Se puede parchear, pero el fork está archivado — nadie publica el fix.
Leyendo los números
El orden es estable a través de cargas de trabajo. gpdf es 10–30× más rápido que la segunda biblioteca en cada caso, lo cual no es ni exótico ni accidental. Tres decisiones de diseño se acumulan:
Layout de una sola pasada. gpdf no construye un AST intermedio para después serializarlo. Los builders escriben al content stream del PDF directamente a medida que se resuelven, lo que elimina aproximadamente la mitad de las asignaciones que hacen las otras bibliotecas. Esto es lo que mueve la aguja en el benchmark de 100 páginas, donde la presión de asignación golpea más al GC — 683 µs contra 19,800 µs no es una diferencia de tuning, es una arquitectura distinta.
Sin reflexión en el hot path. Cada tipo que el motor de layout toca es concreto. Suena a microoptimización — e individualmente lo es — pero acumulado sobre un reporte de 100 páginas, el dispatch por interfaz empieza a aparecer en los perfiles. Lo dejamos fuera.
Subseteador TrueType que no vuelve a recorrer en cada operación. La maquinaria de fuentes de gofpdf relee la tabla cmap en cada lookup de glifo; gpdf resuelve una vez y cachea. Para contenido solo Latin casi no importa. Para CJK, donde un párrafo puede tocar 150 glifos únicos entre Kanji, Hiragana, Katakana y puntuación, es la diferencia entre "rápido para generación síncrona" y "a la cola".
Una advertencia que la tabla no dará: la velocidad absoluta importa menos de lo que la gente piensa para la mayoría de cargas PDF. El umbral interesante es "lo bastante rápido para generar en la ruta de la petición". Todas las bibliotecas de esta comparación superan ese umbral para un hello world de una página. Solo gpdf lo supera para un reporte de 100 páginas con chrome repetido. Si tu documento más grande es un recibo de una página, las cuatro mantenidas están bien; elige por ergonomía de API y licencia.
Dependencias
Lo que imprime go mod graph tras un go get fresco de cada una:
| Biblioteca | Módulos externos | Deps. archivadas transitivas |
|---|---|---|
| gpdf (core) | 0 | — |
| signintech/gopdf | 0 | — |
| gofpdf | 0 (pero ella misma archivada) | sí misma |
| go-pdf/fpdf | 0 (pero ella misma archivada) | sí misma |
| johnfercher/maroto v2 | gofpdf (archivada 2021) | sí — gofpdf |
| unidoc/unipdf | muchas (imagen, crypto, compresión) | ninguna archivada |
Para equipos con una regla de lint "nada de deps archivadas en producción", Maroto v2 hoy falla por su transitivo a gofpdf. Los mantenedores de Maroto llevan más de un año reescribiendo el backend fuera de gofpdf; cuando eso salga, esta fila cambia. Vale la pena revisar el repo de Maroto antes de decidir sobre esta base — el estado puede haberse movido entre cuando escribimos esto y cuando lo lees.
El add-on gpdf-pro (cifrado, PDF/A, firma digital, HTML→PDF) trae golang.org/x/net para parseo HTML. El núcleo de gpdf — sujeto de este benchmark — es cero deps externas; pro es opt-in y se instala aparte.
Licencias
| Biblioteca | Licencia |
|---|---|
| gpdf (core) | MIT |
| gpdf-pro (premium) | Propietaria, comercial |
| signintech/gopdf | MIT |
| johnfercher/maroto v2 | MIT |
| gofpdf | MIT |
| go-pdf/fpdf | MIT |
| unidoc/unipdf | AGPL-3.0 o licencia comercial |
Los términos AGPL de unidoc son estrictos. Si lo usas en un servidor con el que los usuarios interactúan por red, tu código de servidor también tiene que publicarse bajo AGPL — inviable para la mayoría de SaaS de código cerrado. Eso suele dejar la licencia comercial como única opción real, y su precio no es público: planifica una conversación con ventas.
Esto es lo que más se pasa por alto en las comparativas basadas en cantidad de stars de GitHub. unidoc tiene más features y más stars. También tiene una licencia que cierra la puerta a la mayoría de casos comerciales sin una compra. No lo decimos como ataque — su modelo es legítimo y el producto es excelente — pero conviene saberlo antes del go get.
Estado de mantenimiento, en cristiano
- gpdf — mantenedor principal: este equipo (gpdf-dev). Lanzamientos cada 2–4 semanas; roadmap en el repo; CI sobre Go 1.22–1.26; respuesta a issues en pocos días laborables. Tenemos skin in the game.
- signintech/gopdf — activo, cadencia de commits menor. Las issues reciben atención; los PR se fusionan en pocas semanas. Caso de uso principal: generación de bajo nivel.
- Maroto v2 — activo. La reescritura v2 aterrizó en 2023 y es estable. La dependencia en gofpdf se conoce y se está reemplazando; revisa el estado antes de comprometerte.
- gofpdf — archivado el 2021-09-08. Banner en el repo: "This repository has been archived by the owner. It is now read-only." Sin parches de seguridad, sin corrección de bugs.
- go-pdf/fpdf — archivado en 2025. El README recomienda usar otra biblioteca. Escribimos una guía específica: gofpdf está archivado. Aquí está cómo migrar a gpdf..
- unidoc/unipdf — activo, equipo comercial, bien financiado. Soporte enterprise disponible.
Cómo elegir
En lugar de una matriz de features, un árbol de decisión, porque "más features" rara vez es la pregunta correcta:
- "Tengo un código Go que genera facturas, reportes o documentos, quiero MIT, cero deps, y mis documentos a veces tienen CJK." → gpdf.
- "Hago generación PDF de bajo nivel con geometría custom y quiero una biblioteca pequeña, estable y con control manual." → signintech/gopdf.
- "Ya tengo código con sabor Maroto que funciona hoy." → quédate en Maroto v2 hasta que caiga el cambio fuera de gofpdf, luego reevalúa. La API no es el problema.
- "Necesito PDF/A, OCR, redacción, firmas digitales, y mi empleador paga una licencia comercial." → unidoc/unipdf, con la conversación de licencia por delante.
- "Sigo en gofpdf y funciona." → bien hoy. Planifica la migración antes de que caiga el próximo CVE en alguna dep y te quedes varado. Guía de migración.
- "Renderizado HTML/CSS a PDF pixel-perfect." → ninguna de arriba. Usa go-rod o chromedp con Chromium headless, y asume el coste de arranque en frío.
Somos el equipo de gpdf, así que por supuesto pensamos que gpdf es la opción por defecto para el primer grupo y buena parte del quinto. Lee el código de benchmark, córrelo localmente, no te tragues la tabla sin digerirla.
Un ejemplo gpdf de 30 líneas
Porque "la más rápida" y "con el menor grafo de deps" solo importan si el código es soportable. Esta es una página de factura completa y ejecutable — sin pseudocódigo, sin imports omitidos:
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("FACTURA #2026-0042", template.Bold(), template.FontSize(20))
c.Spacer(document.Mm(6))
c.Table(
[]string{"Descripción", "Cant.", "Unit.", "Importe"},
[][]string{
{"Desarrollo frontend", "40 h", "€120,00", "€4.800,00"},
{"Desarrollo backend", "60 h", "€120,00", "€7.200,00"},
{"Diseño UI", "20 h", "€100,00", "€2.000,00"},
},
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)
}
}
Cero SetXY. Cero cálculos manuales de ancho de columna. Cambia "Descripción" por "品目" y añade gpdf.WithFont("NotoSansJP", ttfBytes) a las opciones del documento — renderiza japonés sin ningún otro cambio.
Lo que dejamos fuera
Todo post de comparación tiene una sección "omitido por X". La nuestra:
- Forks privados de gofpdf. Hay forks en producción dentro de empresas. No podemos benchmarkear código que no vemos.
pdfcpu. Está en cada lista de "bibliotecas Go PDF", pero es sobre todo un procesador PDF (merge, split, encrypt, stamp), no un generador. Fuera del alcance de este post; un artículo separado sobre procesamiento está planeado.- Cualquier envoltorio de
gotenbergo servicio de navegador headless. No es una biblioteca. No es una comparación justa. - Nuestros propios benchmarks de
gpdf-pro. Lo que importa para la comparación son los números del core; pro añade features (cifrado, PDF/A), no velocidad en bruto.
FAQ
¿Por qué gpdf es 10× más rápido que gofpdf? ¿Cuál es el truco? Ningún truco único. Se acumulan tres diseños: layout de una pasada (sin AST entre builder y writer), tipos concretos en el hot path, y un subseteador TrueType que cachea la cmap. Cualquiera en aislamiento da un 2×. Apilados, un orden de magnitud.
¿Puedo realmente reproducir el benchmark?
Sí. git clone https://github.com/gpdf-dev/gpdf && cd gpdf/_benchmark && go test -bench=. -benchmem. Si los números no coinciden con los del post — misma arquitectura, misma versión de Go — abre un issue. El drift de benchmarks pasa; preferimos saberlo.
¿Va a volver gofpdf? Realmente no. Último commit de 2021. Issue tracker cerrado. Aunque alguien lo reabriera, la arquitectura (cursor único, fuentes de un byte, sin grid) es el punto de partida equivocado para 2026. Mejor tratarlo como artefacto histórico y migrar.
¿Qué hay de Java iText / Python ReportLab / Node pdfkit? Benchmarks entre lenguajes son otro post. Versión corta: Go generalmente gana en throughput y cold start, pierde en amplitud de features (sobre todo en fidelidad HTML→PDF). Para equipos ya en Go, gpdf es más rápido y más pequeño que cualquiera de esas opciones entre lenguajes; para equipos en Python o Node, el coste de migración suele amortizarse solo a gran volumen.
¿Tiene gpdf una licencia comercial para quien no quiera MIT?
El core es solo MIT. gpdf-pro (el add-on premium con cifrado, PDF/A, firmas, HTML→PDF) es comercial. Si necesitas un acuerdo dual sobre el core, contacta, pero la respuesta por defecto es "MIT te sobra para tu caso, incluido uso comercial".
¿Se mantendrá justa esta comparación si la competencia mejora? Sí. La corremos cada año. Si signintech/gopdf publica una API de tablas que corta su tiempo a la mitad, va en el post de 2027. Si Maroto v2 termina de sacarse gofpdf de encima, esa fila cambia. El código del benchmark es público precisamente para que nadie tenga que creernos sobre la palabra.
Prueba gpdf
gpdf es una biblioteca Go para generar PDFs. MIT, cero dependencias, CJK nativo.
go get github.com/gpdf-dev/gpdf
⭐ Star en GitHub · Leer la documentación
Siguientes lecturas
- gofpdf está archivado. Aquí está cómo migrar a gpdf. — el mapeo completo de API con cinco pares antes/después.
- Quickstart — puesta en marcha en cinco minutos, incluyendo
go.mod. - El código del benchmark:
_benchmark/benchmark_test.go.