Library / SDK
gen2brain/go-fitz avatar
gen2brain/go-fitz

go-fitz: a Go binding for MuPDF that reads PDF, EPUB, DOCX, XLSX and PPTX

Golang wrapper for the MuPDF Fitz library

645 stars137 forksCAGPL-3.0

At a glance

What is it?
go-fitz wraps the MuPDF fitz library for Go so a program can open a document and pull pages out as images, text, HTML or SVG. It ships with a bundled MuPDF build, offers a purego path that needs no cgo, and warns that the bundled libraries have no CJK fonts.
Who is it for?
go-fitz suits a Go service that needs to pull pages or text out of office and ebook documents without shelling out to a converter, and the purego build tag is the reason it can do that in a static binary with CGO_ENABLED=0.
Can I use it commercially?
Yes, with strict conditions. AGPL-3.0 is a network copyleft licence: if people use a modified version over a network, for example as a hosted service, you must offer them its source code under the same licence.
Is it still maintained?
Yes. The repository last received commits 109 days ago.
What is it written in?
Mainly C, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

One document API across six file formats

The description says it plainly: a Go wrapper for the MuPDF fitz library that can extract pages from PDF, EPUB, MOBI, DOCX, XLSX and PPTX documents as IMG, TXT, HTML or SVG. That pairing of things is the value. A Go program that needs to read a PDF and also needs to read a DOCX or an EPUB would otherwise need a converter per format, each a separate binary, a separate process boundary and a separate set of failure modes. With fitz, the document is opened through one constructor and pages come out through one set of methods, and the format list follows what MuPDF itself handles. The repository layout matches the shape of the binding. There is a fitz.go for the shared surface, fitz_cgo.go for the cgo path, fitz_cgo_extlib.go and fitz_cgo_extlib_pkgconfig.go for the external library variants, fitz_nocgo.go for the purego path, and fitz_vendor.go for the bundled build, plus a fitz_content_types.go with its own test file. The include and libs directories hold the C headers and the prebuilt shared libraries, and there are per-platform files for purego on darwin, linux and windows and for stderr and struct marshalling.

Five build tags decide where MuPDF comes from

The build tags are the first decision a user makes, and the README lists five. The extlib tag uses an external MuPDF library, and static builds with a static external MuPDF library and is used with extlib. The pkgconfig tag enables pkg-config and is also used with extlib. The musl tag uses a musl compiled library, which matters if you are producing a static binary against Alpine. And nocgo is an experimental purego implementation, which the README notes can also be used with CGO_ENABLED=0. The practical shape of this is that a default build uses the vendored libraries, so the module works out of the box, while extlib and pkgconfig let you point at a system MuPDF instead, which is what you want when you need a build with CJK fonts or a specific MuPDF version. The module file confirms the dependency surface is tiny: purego at 0.10.1 and golang.org/x/sys at 0.33.0, with a go directive of 1.24.0. There is no PDF parsing library in the dependency list, because MuPDF does all of that work.

The example is a page-to-JPEG loop

The README's example is short enough to read in full and it shows the shape of the API. A document is opened with fitz.New, the file name is passed directly, and the error is checked. The document is closed with a deferred Close. Pages are then walked with a loop over doc.NumPage(), and each page is rendered with doc.Image(n), which returns an image value the caller encodes. The loop writes each page into a temporary directory created with os.MkdirTemp under os.TempDir(), with the file name built by fmt.Sprintf into test%03d.jpg, and the image is encoded with jpeg.Encode at jpeg.DefaultQuality. The same Document object exposes the other output formats named in the description, so Text, HTML and SVG come from the same handle and the same page index. The opening of the example looks like this:

go
func main() {
	doc, err := fitz.New("test.pdf")
	if err != nil {
		panic(err)
	}

	defer doc.Close()

	tmpDir, err := os.MkdirTemp(os.TempDir(), "fitz")
	if err != nil {
		panic(err)
	}

	// Extract pages as images
	for n := 0; n < doc.NumPage(); n++ {

The pattern to notice is that there is no page object to manage: the page number is the handle, and the document owns the underlying MuPDF context.

Concurrency has a hard rule attached to it

The Notes section states two constraints that decide whether go-fitz can be used in a server. Concurrent rendering is supported when each goroutine uses its own Document, meaning a separate MuPDF context, and concurrency on a single Document, including racing with Close, is not supported. That is a specific and reasonable design. A MuPDF context holds mutable state, so sharing one across goroutines is a data race, and the alternative of a pool of contexts is expensive. The rule for an application is therefore simple but not optional: one Document per goroutine, or one Document per worker, and never a shared one. A service that opens a document per request naturally satisfies this. A service that opens a document once and fans requests out over it does not, and the failure would be a race rather than a clean error. The README also notes that the purego implementation loads the libmupdf shared library at runtime, that its version is detected automatically, and that you can override that detection with the FZ_VERSION environment variable or fitz.FzVersion.

The bundled libraries have no CJK fonts

This is the one line in the README that will save you a debugging session. The bundled libraries are built without CJK fonts, and if you need them you must use the external library. In other words, the default build renders Latin text and leaves Chinese, Japanese and Korean documents blank or tofu, and the fix is not a configuration flag but a different linking strategy. That is what the extlib and pkgconfig tags are for, and it is also why the external library path matters for more than version control. It reframes the build tag choice: extlib is not there to avoid vendoring a large library, it is there to let you supply a MuPDF built with the fonts your documents need. The same note also implies a second consequence, since a document that renders without visible glyphs is not an error condition that the wrapper can detect, the failure appears as an empty or garbled image rather than as a returned error.

What the AGPL licence means for a Go dependency

The licence is AGPL-3.0, and for a Go binding that is the fact most likely to need a conversation with a lawyer before adoption. The AGPL is the copyleft licence designed to reach network use, so linking go-fitz into a server that users interact with over a network brings the corresponding obligations on the combined work. Whether that matters depends entirely on how the tool is deployed, and the wrapper being a Go library rather than a separate process does not obviously answer the question, because the obligations attach to the combined work rather than to the deployment shape. No legal advice is offered here and the practical step is to read the COPYING file at the repository root, which sits next to an AUTHORS file. The rest of the metadata is unremarkable. The repository publishes no GitHub releases, the default branch is master, the last push was on 2026-07-06, and the badges point to a test workflow, godoc documentation, a Go Report Card entry.

Where go-fitz is the wrong choice

Three boundaries are worth stating. The first is the CJK font problem, which makes the bundled build unusable for a large part of the world's document corpus unless you switch to an external MuPDF and accept the extra build complexity. The second is that go-fitz is a page extraction and rendering library, not a document understanding tool. It will hand you a page as an image or a text stream, and it will not tell you what the document means. If the requirement is to pull a table out of a spreadsheet or a field out of a form, that is a different kind of library, and the wrapper's format list should not be read as a promise of semantic extraction. The third is the AGPL question, which for a closed-source commercial product is a licensing obstacle rather than a technical one, and which no amount of engineering in the wrapper will remove. The alternative worth naming here is a PDF library under a permissive licence, which will be narrower in format coverage but will not raise the copyleft question, and the choice between them is usually made on licence grounds before it is made on capability.

Editorial conclusion

go-fitz suits a Go service that needs to pull pages or text out of office and ebook documents without shelling out to a converter, and the purego build tag is the reason it can do that in a static binary with CGO_ENABLED=0. It is the wrong tool if your documents contain Chinese, Japanese or Korean text, because the bundled libraries are built without CJK fonts and you must switch to an external MuPDF build, and it is the wrong tool for concurrent work on a single document, since concurrency is only supported when each goroutine uses its own Document. Verify first which MuPDF you will link against and whether the extlib and static build tags suit your deployment, and note that the licence is AGPL-3.0, which is a decision your legal team needs to make before this goes into a closed-source product.

Frequently asked questions

Which document formats can go-fitz read?

The README says it can extract pages from PDF, EPUB, MOBI, DOCX, XLSX and PPTX documents as IMG, TXT, HTML or SVG.

Can go-fitz be used without cgo?

Yes. The nocgo build tag enables an experimental purego implementation, and the README notes it can also be used with CGO_ENABLED=0. The purego path loads the libmupdf shared library at runtime and detects its version automatically.

Does go-fitz support Chinese, Japanese and Korean documents?

Not with the bundled libraries. The README states they are built without CJK fonts, and that if you need them you must use the external library, which is what the extlib and pkgconfig build tags are for.

Is go-fitz safe to use from multiple goroutines?

Concurrent rendering is supported when each goroutine uses its own Document with a separate MuPDF context. Concurrency on a single Document, including racing with Close, is not supported.

Under what licence is go-fitz released?

AGPL-3.0, with the full text in the COPYING file at the repository root alongside an AUTHORS file.

Official sources

  1. gen2brain/go-fitz on GitHub
  2. Issues
  3. License: AGPL-3.0
  4. README
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/gen2brain-go-fitz.svg)](https://hysenlabs.com/projects/gen2brain-go-fitz)

Was this useful?