# libvips: a demand-driven C image library for low-memory pipelines

> libvips is a demand-driven, horizontally threaded image processing library written in C, with around 300 operations and bindings for a dozen languages. It suits batch and server-side pipelines that need to resize or convert images without loading them fully into memory.

**libvips/libvips** — A fast image processing library with low memory needs.

- Repository: https://github.com/libvips/libvips
- Website: https://libvips.org
- Stars: 11,696 · Forks: 803
- Language: C
- License: LGPL-2.1
- Published: 2026-09-21 · Updated: 2026-09-21 · Language: en
- Canonical page: https://hysenlabs.com/projects/libvips-libvips

## The memory problem libvips is built to avoid

Most image libraries you meet first in a project, such as Pillow or ImageMagick, work on a full decoded pixel buffer. A 10,000 by 10,000 RGB image is roughly 300 MB in memory before any processing, and a resize can briefly need more than one copy. On a worker that handles concurrent uploads, that number multiplies by the number of in-flight jobs.

libvips takes a different route. The README describes it as a "demand-driven, horizontally threaded" library, and links to a wiki page titled Why is libvips quick. Demand-driven means operations are not executed when you call them. You build a graph of operations, and pixels are pulled through that graph only when a consumer asks for a region of output. A thumbnail operation can therefore decode only the part of the source it needs, at the resolution it needs, instead of decoding the full image and shrinking it afterwards.

The audience follows from that design. libvips is aimed at people writing image pipelines where throughput and resident memory matter: thumbnail services, upload processing in a web backend, batch conversion jobs. The README lists Mastodon, sharp on Node.js, imgproxy, wsrv.nl, bimg, Ruby on Rails Active Storage, CarrierWave and MediaWiki's Thumbro extension as users of libvips as an image processing engine. That list is a signal about the kind of workload it was built for, not a quality claim.

It is not a general numerical or vision library. The README describes around 300 operations covering arithmetic, histograms, convolution, morphological operations, frequency filtering, colour, resampling and statistics. There is no mention of feature detection, object detection or matrix algebra for machine learning, so a project that needs those should look elsewhere.

## How the demand-driven pipeline actually works

The core abstraction is the image object plus the operation graph. When you write a chain such as load, resize, sharpen, save, libvips records the operations rather than running them. Each operation declares how to produce a rectangular region of its output from regions of its inputs. The final consumer, usually a writer, requests tiles, and the request propagates backwards through the chain.

Two consequences are visible in the README. First, memory use is bounded by the size of the regions in flight plus any caches, not by the size of the full decoded image. Second, the work is horizontally threaded: the library splits a request across threads, which is why the README points to a separate wiki page on speed and memory use. The threading is internal to the library, so a caller does not have to tile the image manually.

The type system is wider than most image libraries. The README states that libvips supports numeric types from 8-bit int to 128-bit complex, and that images can have any number of bands. That matters for scientific and remote-sensing formats such as FITS, Matlab, OpenEXR and NIfTI, which appear in the supported format list. It also means the library is not restricted to the usual 8-bit RGB assumption that many web-oriented tools bake in.

Format support is layered rather than monolithic. The README lists JPEG, JPEG 2000, JPEG XL, TIFF, PNG, WebP, HEIC, AVIF, FITS, Matlab, OpenEXR, PDF, SVG, HDR, PPM/PGM/PFM, CSV, GIF, Analyze, NIfTI, DeepZoom and OpenSlide. For several of these, libvips prefers a specific library and falls back to ImageMagick or GraphicsMagick if that library is absent. PDF is the clearest example: the README says libvips will try PDFium first, then poppler-glib, then ImageMagick. The practical effect is that two machines with the same libvips version can behave differently on the same file, because the loader chosen depends on what was present at build time.

## Installing libvips and running a first resize

The README does not give a single canonical install command. It says there are packages for most Unix-like operating systems, including macOS, and tells you to check your package manager. For Windows, it points to binaries in the GitHub releases. Detailed install notes live on the libvips website.

After installing, the command-line tool should be on your PATH. The README links to a page on using the CLI, and the repository ships a man/ directory. A first real use is generating a thumbnail, which is the workload the demand-driven design targets. The README's CLI documentation is the place to check the exact argument order for the thumbnail operation on your build.

If you need to build from source, the README gives a Meson cheatsheet. Meson 0.56 or later is required, and the build needs build-essential, pkg-config, libglib2.0-dev and libexpat1-dev on a Debian-like system.

```bash
cd libvips-x.y.x
meson setup build --prefix /my/install/prefix
cd build
meson compile
meson test
meson install
```

The README warns you to read the output of meson setup carefully, because optional dependencies are detected automatically and a missing library silently removes format support. Build options such as -Dnsgif=false and -Dmagick=disabled are set through meson_options.txt, which the README points to for the full list. If you want a static library, the README mentions --default-library static. There is also a larger test suite you can run with pytest from the libvips base directory once the library is installed.

## Where libvips is the wrong tool

The first limitation is dependency shape. libvips is a C library with a long list of optional dependencies, and the README's install section assumes you are on a system with a package manager or that you are prepared to run Meson and track down development headers. There is no single-file, zero-dependency distribution described. If your deployment target is a minimal container or an environment where you cannot add system packages, that is friction you will feel on every upgrade.

The second is behavioural drift between builds. Because loaders are selected at build time from whatever pkg-config finds, the same libvips version can decode a PDF through PDFium on one host and through poppler-glib or ImageMagick on another. The README documents this fallback chain explicitly, which is helpful, but it also means your test environment and production environment can disagree about a file without any version difference in libvips itself.

The third is scope. libvips is an image processing library in the signal-processing sense: arithmetic, histograms, convolution, morphology, colour, resampling, statistics. If your task is detecting objects, matching features or running a neural network, this is not the library for that job, and the README does not claim otherwise.

Finally, the licence. libvips is LGPL-2.1-or-later. That is a copyleft licence with a linking exception structure that many commercial products do use, but it is not the permissive MIT or BSD terms that some teams assume by default. Whether your distribution model is compatible is a question for your own legal review, not something the README answers.

## libvips versus ImageMagick, Pillow and OpenCV

The most common comparison is libvips against ImageMagick, and the difference is architectural rather than cosmetic. ImageMagick's core model is a decoded image in memory that you mutate with operations; libvips builds a graph and pulls pixels on demand. The README's own framing of libvips as demand-driven and low-memory is a direct contrast with that model, and the project maintains a wiki page specifically comparing speed and memory use against similar libraries. The trade-off is that libvips asks you to think in terms of pipelines and lazy evaluation, which is a different mental model from imperative pixel manipulation.

Against Pillow, the difference is again memory and language. Pillow is a Python library that decodes to a buffer; pyvips is a binding to the C library, so the heavy lifting happens outside the interpreter and the GIL. The README lists pyvips on PyPI as the full Python binding. If your pipeline is already Python and your images are small, Pillow's ergonomics may be worth more than libvips's memory profile. If your images are large or your concurrency is high, the buffer-per-image model is the thing you are trying to escape.

Against OpenCV, the split is domain. OpenCV targets computer vision: feature detection, camera calibration, classical and learned vision algorithms. libvips targets format handling, resampling, colour and pixel arithmetic at scale. The README's operation list contains no vision primitives, so choosing libvips for a vision task means choosing the wrong tool, and choosing OpenCV for a thumbnail service means paying for machinery you will not use.

sharp on Node.js is worth naming separately because the README lists it as a user of libvips rather than a competitor: it is a Node binding that wraps libvips. The same is true of bimg for Go and the various language bindings in the README's table. For most application developers, the realistic choice is not libvips against these tools but which binding to use.

## Maintenance, releases and the cost of upgrading

The repository is not archived, and the last push was on 2026-09-19. The most recent releases listed are v8.18.6 on 2026-08-25, v8.18.5 on 2026-08-03 and v8.18.4 on 2026-07-05. The cadence over that window is roughly one patch release per month, which tells you the project is issuing fixes rather than sitting still.

Upgrade cost depends on how you consume it. If you install through a package manager, you inherit your distribution's version and its build-time dependency choices, and an upgrade can change which loader handles a given format. If you build from source, you own the Meson configuration and therefore own the format support matrix. The README's advice to read meson setup output carefully is really upgrade advice: a dependency that disappears between builds removes a format silently.

The bindings add a second version axis. pyvips, ruby-vips, php-vips, NetVips, vipsgen, lua-vips, crystal-vips, vix, vips-ffm, libvips-nim and vips-rs are separate projects with their own release schedules, and they each need a compatible libvips underneath. A binding upgrade can therefore force a system library upgrade, which is the kind of coupling that shows up late in a release cycle.

On licensing, LGPL-2.1-or-later is the term the README states. It is worth reading the actual licence text and your own distribution obligations rather than relying on a summary, and this article does not give legal advice. The practical question for most teams is whether they dynamically link against libvips or ship a modified copy, since those are different situations under a copyleft licence.

## Conclusion

Adopt libvips when you are building a server-side or batch pipeline that resizes, converts or filters images and memory per request is the constraint. Do not adopt it if you need pixel-level computer vision primitives, or if you want one self-contained binary with no system dependencies. Before committing, verify that your package manager or release binary gives you the format loaders you actually need, since the README states libvips falls back to ImageMagick or GraphicsMagick for several formats when the preferred library is missing, and check whether you can ship an LGPL-2.1-or-later dependency in your product.

## FAQ

### What is libvips?

libvips is an image processing library written in C, described in its README as demand-driven and horizontally threaded, with around 300 operations and support for a wide range of image formats. It is licensed under LGPL-2.1-or-later and ships bindings for C, C++, the command line and a dozen other languages.

### How do I install libvips?

The README says there are packages for most Unix-like operating systems, including macOS, and tells you to check your package manager; for Windows it points to binaries in the GitHub releases. Detailed install notes are on the libvips website, and building from source uses Meson 0.56 or later.

### How do I install libvips on Windows?

The README states that there are binaries for Windows in the project's GitHub releases. It does not describe a Windows package manager route, and the Meson build instructions it gives are the generic source build rather than a Windows-specific procedure.

### What image formats are supported by libvips?

The README lists JPEG, JPEG 2000, JPEG XL, TIFF, PNG, WebP, HEIC, AVIF, FITS, Matlab, OpenEXR, PDF, SVG, HDR, PPM/PGM/PFM, CSV, GIF, Analyze, NIfTI, DeepZoom and OpenSlide, and notes it can also load images via ImageMagick or GraphicsMagick for formats such as DICOM.

### How do I use libvips?

You can use it through the C, C++ or command-line interfaces described in the README, or through one of the full bindings it lists for languages including Ruby, Python, PHP, C#/.NET, Go, Lua, Crystal, Elixir, Java, Nim and Rust. The README links to pages covering use from C, C++ and the CLI.

## Sources

- [libvips/libvips on GitHub](https://github.com/libvips/libvips)
- [License: LGPL-2.1](https://github.com/libvips/libvips/blob/master/LICENSE)
- [Project website](https://libvips.org)
- [README](https://github.com/libvips/libvips/blob/master/README.md)
- [Releases](https://github.com/libvips/libvips/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/libvips-libvips
