Library / SDK
davidbyttow/govips avatar
davidbyttow/govips

govips binds libvips, and the cgo flags are part of the API

A lightning fast image processing and resizing library for Go

1,678 stars220 forksGoMIT

At a glance

What is it?
govips is a Go binding for libvips, wrapping image operations as first class types. Getting it to build means installing libvips 8.14 or newer, having a C compiler, and on macOS exporting CGO_CFLAGS_ALLOW before anything compiles.
Who is it for?
govips suits Go services that resample, thumbnail or transcode images under concurrent load, where a native libvips dependency in your build image is an acceptable cost. It does not suit a deployment that must ship a single static binary with no system libraries, and it does not suit Windows, where the README recommends WSL and says native builds are untested and not in CI.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 7 days ago.
What is it written in?
Mainly Go, 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

Startup and Shutdown bracket every program

govips is a cgo binding, so the library has a process level lifecycle that other Go packages do not. Every example in the README opens the same way, with an explicit startup call and a deferred shutdown:

go
package main

import (
	"fmt"
	"os"

	"github.com/davidbyttow/govips/v2/vips"
)

func main() {
	vips.Startup(nil)
	defer vips.Shutdown()

That pairing matters under concurrency, which the README names as the reason to reach for this library in Go: a service handling many simultaneous image requests needs a native processor that fits the concurrency model rather than spawning an external process per request.

The libvips version it targets is 8.14 or newer, with a C compatible compiler such as gcc 4.6 or clang 3.0, and Go 1.23 or newer. go.mod declares the module as github.com/davidbyttow/govips/v2 with a go directive of 1.25.0, so the language floor in the module file is actually higher than the requirement in the README.

The macOS build needs an environment variable set by hand

This is the most common first failure and the README gives it its own subsection. On macOS, govips may not compile without first setting an environment variable:

bash
export CGO_CFLAGS_ALLOW="-Xpreprocessor"

The Makefile shows how the maintainers handle the same class of problem during builds, setting CGO_CFLAGS_ALLOW to a broader pattern on every target:

bash
CGO_CFLAGS_ALLOW='-I.*' go build -v ./vips

So a CI system needs either the variable exported in the job environment or the same treatment baked into its build command. It is a cgo restriction rather than something specific to govips, but because govips is a cgo package it inherits the restriction, and a developer working only on Linux will not hit it.

Installation itself is one line, and the v2 path in the import path is what makes the version explicit:

bash
go get -u github.com/davidbyttow/govips/v2/vips

A code generator covers the operations, hand written code covers the formats

The project status section describes an unusual hybrid. govips ships a built-in code generator at cmd/vipsgen/ that uses libvips GObject introspection to auto-generate type-safe Go bindings, covering 193 or more operations across nine categories: arithmetic, colour, conversion, convolution, create, freqfilt, histogram, morphology and resample.

Complex operations such as image I/O are excluded from generation and remain hand written, and the stated reason is full control. That split is the design decision worth understanding before you build on it. Generated bindings mean the long tail of operations follows libvips naming and signatures closely, so a libvips document applies directly. Hand written I/O means the export calls are where you find the library's own opinions.

The hand written layer is what most users touch first. Export takes typed parameter structs, and the constructors exist for defaults:

go
buf, _, err := image.ExportJpeg(&vips.JpegExportParams{Quality: 85})

There are parallel structs for the other formats, WebpExportParams and PngExportParams among them, each with a New-style constructor for the default case.

NewThumbnailFromFile decodes only the pixels it needs

The thumbnail path is the one the README calls out as fastest, and the reason is architectural rather than algorithmic. NewThumbnailFromFile decodes only the pixels it needs, rather than loading the whole image and shrinking it afterwards:

go
image, err := vips.NewThumbnailFromFile("photo.jpg", 200, 200, vips.InterestingAttention)

The third argument is the interestingness strategy, and InterestingAttention asks for the most interesting region rather than the centre. That is a cropping policy decision baked into a load operation, which is why it cannot be applied after the fact.

The alternative path, which the README documents separately, is to load the file and then resize it, optionally with a named kernel:

go
if err := image.Resize(0.5, vips.KernelLanczos3); err != nil {
	log.Fatal(err)
}

KernelLanczos3 is described as the sharpest option. The trade-off between the two is memory and decode cost on one side and flexibility on the other, and for a user interface thumbnail grid the first wins clearly.

EXIF rotation is a separate call, and forgetting it flips photos

The first example loads an image, then does something easy to overlook:

go
image, err := vips.NewImageFromFile("input.jpg")
if err != nil {
	log.Fatal(err)
}

// Fix orientation from EXIF metadata
if err := image.AutoRotate(); err != nil {
	log.Fatal(err)
}

Phone cameras record orientation in EXIF rather than rotating pixels, so a loader that ignores it produces sideways images from a large share of real uploads. AutoRotate is not part of loading in this library, which means every service that accepts user uploads has to remember it.

The same applies to stripping metadata, which the examples do not cover. If you serve user images, you need to decide explicitly whether EXIF survives, and this library gives you the primitives rather than a default.

Rotation is otherwise available as a fixed-angle call, with vips.Angle90 for a quarter turn clockwise, and flipping along an axis with vips.DirectionHorizontal. Colour adjustment goes through Modulate, which the README says works in the LCH colour space, where brightness and saturation are multipliers with 1.0 meaning no change, and hue is an angle shift in degrees.

Windows is not a target, and the README says so

The Windows section is the clearest statement of platform boundaries in the project. The recommended approach is to use govips via WSL and Ubuntu. For native Windows, the README says it is not difficult but requires effort, that there is no recommended environment or setup at the moment, and that Windows is not in the list of CI/CD targets, so govips is not regularly tested for compatibility there.

It goes further and invites a contribution: if you would be willing to set up and maintain a robust CI/CD Windows environment, open a pull request. That is an honest description of an unfunded platform, and it is more useful than a silent gap.

macOS has a documented install path through homebrew, installing both vips and pkg-config:

bash
brew install vips pkg-config

The test target in the Makefile runs the suite with coverage, so contributors have a single command, and clean-cache and distclean exist for when a stale build cache is suspected. The licence is MIT, and the recent release cadence is regular, with v2.19.0 published on 2026-09-20 and v2.18.0 on 2026-04-01. The last push was on 2026-10-16.

Editorial conclusion

govips suits Go services that resample, thumbnail or transcode images under concurrent load, where a native libvips dependency in your build image is an acceptable cost. It does not suit a deployment that must ship a single static binary with no system libraries, and it does not suit Windows, where the README recommends WSL and says native builds are untested and not in CI. Before adopting, confirm your build pipeline can install libvips and export CGO_CFLAGS_ALLOW on macOS, since the README states govips may not compile without it.

Frequently asked questions

What do I need before govips will build?

libvips 8.14 or newer, a C compatible compiler such as gcc 4.6 or clang 3.0, and Go 1.23 or newer. go.mod declares a go directive of 1.25.0 for the module itself.

Why does govips fail to compile on macOS?

The README states that on macOS govips may not compile without first setting the environment variable `export CGO_CFLAGS_ALLOW="-Xpreprocessor"`. Its own Makefile sets CGO_CFLAGS_ALLOW on the build and test targets.

How do I install govips and what is the import path?

Run `go get -u github.com/davidbyttow/govips/v2/vips` and import github.com/davidbyttow/govips/v2/vips. The v2 path in the module name keeps the major version explicit.

Is Windows supported by govips?

The README recommends WSL with Ubuntu and says native Windows is not regularly tested for compatibility, since Windows is not among the CI/CD targets. It invites a pull request from someone willing to maintain a Windows CI environment.

Official sources

  1. davidbyttow/govips on GitHub
  2. Issues
  3. License: MIT
  4. README
  5. Releases
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/davidbyttow-govips.svg)](https://hysenlabs.com/projects/davidbyttow-govips)

Was this useful?