This guide reviews the top PDF generation packages for Go. We'll explore their features, evaluate their likely performance, and help you find the best fit for your project's needs.
When it comes to generating PDFs, there are two common approaches: HTML to PDF conversion libraries or low-level PDF builders. As the name suggests, HTML to PDF conversion libraries convert HTML code into a PDF document. They are favored due to their simplicity and speed, allowing developers to design documents using familiar HTML and CSS before converting them to PDF format.
Low-level builders force you to create your PDF text block by text block, image by image, line by line. Theoretically, low-level API builders offer more granular control over your PDF creation. In practice, builders are more complex and time-consuming, and we strongly recommend an HTML-based conversion approach. And for more complex documents, you should try an HTML to PDF generator that fully supports CSS Paged Media.
There are two sub-types for the conversion libraries. Browser-based libraries, such as those based on Google Chromium, operate by automating an actual browser to render the HTML and CSS, and then capturing that rendering as a PDF. This approach guarantees the latest CSS and JavaScript capabilities and perfectly matches what you'd see in a web browser. However, this accuracy comes at a cost. Browser-based libraries often require more system resources and can be slower, since they require launching and controlling a whole web browser.
Alternatively, non-browser-based libraries typically offer more PDF-specific related functionality and broader support for the CSS Paged Media specifications. They may lack cutting-edge JavaScript functionality and render slightly differently than the browsers, but they make up for it in power and flexibility. These non-browser libraries often provide better support for varying headers and footers, page sizing, table of contents, first page styling, and more.
Rod and Chromedp are popular PDF generation libraries in Go that operate on the browser-based approach, leveraging the capabilities of Google's Chromium engine. They're similar to Node's Puppeteer library. Their most significant advantage is that they provide the latest in modern JavaScript and CSS with the common weakness of little document-related functionality and aggressive use of server resources. These tools are excellent for documents based on SPA projects or that require charting libraries.
Rod has an article comparing Rod to other Chromium-based libraries, including Chromedp.
GoFPDF is a low-level builder library for generating PDFs in Go. This library offers you the flexibility and control to define every element in your PDF. It supports UTF-8 fonts, embedding images, and generating tables directly. It even allows drawing of cells and line breaks for text (yes, these features are a big deal for a low-level builder, whereas it's never an issue with an HTML-based converter). The trade-off to this level of control is the complexity of use. You'll need to define everything from scratch, and creating complex documents will be time-consuming. Unfortunately, the GoFPDF project was archived back in 2021, with the maintainers seeming to consider the project complete.
Maroto, which is built upon GoFPDF, takes a slightly different approach. It provides a simple interface for generating PDFs based on the Bootstrap framework. It compensates for Gofpdf's arduous development with predefined layouts, automatic line breaks, and a simplified API for adding images, headers, and footers. While it does not offer as much granular control as Gofpdf, it reduces the time and effort required to create a PDF document. Maroto is still in active development, despite Gofpdf's status.
Not to be confused with GoFPDF, gopdf is another low-level builder. It has a much smaller feature set than GoFPDF but is still maintained. We'd only try it on the simplest PDF documents.
As you've likely noticed, Go doesn't provide great PDF generation options outside the Chromium-based packages. Fortunately, excellent non-Go options also exist. Both of these alternatives are non-browser-based HTML to PDF conversion tools, but neither use Go:
WeasyPrint is written in Python, but is the best open-source HTML to PDF library that is not browser-based. It lacks any support for JavaScript and only provides a subset of the PDF-specific functionality that DocRaptor and Prince offer. It does support more of CSS Paged Media than any of Google Chromium tools will provide.
Unlike the libraries above, we're an API, with the typical advantages of an online HTML to PDF API. Namely, we provide instant scalability and redundancy and remove all maintenance work. Our partnership with the Prince PDF library means we offer full CSS Paged Media support as well as PDF forms and accessible PDFs. DocRaptor makes it easy to create documents that are difficult or impossible to create in other PDF generators.
While we're not Go-based, it's easy to call our API directly in Go:
package main
import (
"bytes"
"io"
"io/ioutil"
"log"
"net/http"
"os"
)
const docraptorAPIKey = "YOUR_API_KEY_HERE" // This key actually works!
const docraptorURL = "https://docraptor.com/docs"
func main() {
payload := []byte(`{
"document_content": "Hello World",
"document_type": "pdf",
"test": true
}`)
// Create a new request
req, err := http.NewRequest("POST", docraptorURL, bytes.NewBuffer(payload))
if err != nil {
log.Fatalf("Failed to create request: %v", err)
}
req.Header.Set("Content-Type", "application/json")
req.SetBasicAuth(docraptorAPIKey, "")
// Send the request
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
log.Fatalf("Failed to send request: %v", err)
}
defer resp.Body.Close()
// Check if the response is successful
if resp.StatusCode != http.StatusOK {
log.Fatalf("Failed to generate PDF: %v", resp.Body)
}
// Read the response body
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Fatalf("Failed to read response body: %v", err)
}
// Write the body to a file
file, err := os.Create("example_document.pdf")
if err != nil {
log.Fatalf("Failed to create file: %v", err)
}
defer file.Close()
_, err = io.Copy(file, bytes.NewReader(body))
if err != nil {
log.Fatalf("Failed to write to file: %v", err)
}
log.Println("PDF successfully created!")
}
Go offers a variety of libraries for generating PDFs, each with its own strengths and drawbacks. Choosing the right tool ultimately rests on your specific needs, whether it's the granular control of a low-level builder, the modern compatibility of a browser-based library, or the ease and scalability of an API.
Our strongest recommendation is to evaluate the most complex parts of your document first and calculate the total cost of development and maintenance. This exercise will quickly eliminate generation options that cannot meet your needs and highlight the most cost-effective generators.