# spatie/image-optimizer: a PHP wrapper around the image binaries you already know

> This package does not compress anything itself. It detects which command line optimizers are installed on the host and pipes your files through them, which makes it a good fit for PHP pipelines that already have jpegoptim, pngquant and friends on the box.

**spatie/image-optimizer** — Easily optimize images using PHP

- Repository: https://github.com/spatie/image-optimizer
- Website: https://freek.dev/797-easily-optimize-images-using-php-and-some-binaries
- Stars: 2,879 · Forks: 225
- Language: PHP
- License: MIT
- Published: 2026-09-28 · Updated: 2026-09-28 · Language: en
- Canonical page: https://hysenlabs.com/projects/spatie-image-optimizer

## The problem: PHP has no good native image compressor

PHP's own image extensions decode and re-encode, but they do not do the kind of byte-level squeezing that jpegoptim or pngquant do. Those tools work on the container format itself: they strip metadata, retry compression parameters, requantize colour tables. Reimplementing that in userland PHP would be slow and would drift from upstream behaviour.

spatie/image-optimizer takes the other route. It is a coordination layer. You hand it a path, it decides which external binary suits that file type, and it runs the binary against the file. The README states plainly that the image at the path you pass "will be overwritten by an optimized version which should be smaller", and that the package "will automatically detect which optimization binaries are installed on your system and use them".

The audience follows from that. This is for PHP developers running their own servers, containers or CI images where they can install system packages. It is not for shared hosting where you cannot run apt-get, and it is not for a browser-side or SaaS upload flow.

## How the optimizer chain picks binaries per format

The entry point is OptimizerChainFactory::create(), which returns a chain object. The chain holds an ordered list of optimizers, and each one declares which mime types it handles. When you call optimize($path), the chain inspects the file, selects the optimizers whose mime types match, and runs them in sequence. The README's usage example shows exactly this two-line flow.

Because detection happens at runtime, the same code behaves differently on different machines. A developer laptop with only jpegoptim installed will silently skip PNG handling. A production container with the full set will do more work. That is convenient, and it is also the main operational hazard: nothing in the call site tells you which tools actually ran.

The per-format settings are opinionated and documented. JPGs go through JpegOptim with -m85, --strip-all and --all-progressive. PNGs go through Pngquant 2 with its defaults, then Optipng with -i0 and -o2. GIFs go through Gifsicle with -O3, which the README calls "the slowest but best results". SVGs are minified by SVGO using its default configuration minus the cleanupIDs and removeViewBox plugins, because those are "known to cause troubles when displaying multiple optimized SVGs on one page". WEBPs use cwebp with -m 6, -pass 10, -mt and -q 90. AVIFs use avifenc with a constant-quality configuration including -a cq-level=23, -j all and -a tune=ssim.

The chain is sequential and in-place. Each optimizer rewrites the same file, so the next one in the chain reads the output of the previous one. For PNG that means pngquant's lossy requantization happens first, then optipng's lossless pass works on the already-reduced palette.

## Installing the package and the binaries it depends on

Install the PHP side with Composer. The README gives no version constraint, so the default latest release applies.

```bash
composer require spatie/image-optimizer
```

That alone gets you the classes but not the compression. The README lists the binaries the package looks for: JpegOptim, Optipng, Pngquant 2, SVGO 1, Gifsicle, cwebp and avifenc. On Ubuntu or Debian the documented install is a set of apt calls plus a global npm install for SVGO.

```bash
sudo apt-get install jpegoptim
sudo apt-get install optipng
sudo apt-get install pngquant
sudo npm install -g svgo
sudo apt-get install gifsicle
sudo apt-get install webp
sudo apt-get install libavif-bin # minimum 0.9.3
```

Note the comment on the last line: the README requires libavif-bin 0.9.3 or newer for the avifenc options it passes. On macOS the same set comes from Homebrew (brew install jpegoptim, optipng, pngquant, gifsicle, webp, libavif, plus npm install -g svgo). Fedora, RHEL and CentOS use dnf, with epel-release first and libwebp-tools and libavif-tools instead of the Debian package names.

A first real use is the README's own example. Point it at one file and the file changes on disk.

```php
use Spatie\ImageOptimizer\OptimizerChainFactory;

$optimizerChain = OptimizerChainFactory::create();

$optimizerChain->optimize($pathToImage);
```

After this returns, $pathToImage holds the optimized bytes. There is no return value to inspect and no report of what changed. If the file is smaller, the binaries did their job; if a needed binary is missing, that optimizer was skipped without an error surfacing at the call site.

## Where the chain model breaks down

The most consequential limitation is that optimize() overwrites the input. There is no documented backup, no option to write to a second path, and no rollback described in the README. If you want the original, you copy it yourself before calling. In an upload handler that means your pipeline needs its own staging step, because the package will not give you one.

The second limitation is the SVGO warning the README carries in its own words: "Please be aware that SVGO can break your svg." The package mitigates two known problem plugins by omitting them, but it does not guarantee that minification preserves rendering. SVG is a format where a minifier can change visual output, and this package delegates that risk to SVGO rather than containing it.

Third, the silent-skip behaviour cuts both ways. Automatic detection is what makes the package portable, but it also means a deployment that loses pngquant in a base image upgrade will keep returning success while producing larger PNGs. Nothing in the documented API raises an error for a missing binary.

Finally, the quality targets are fixed at the values in the README. JPGs are stored at 85 percent quality with all EXIF stripped, which is a reasonable default for web delivery and a bad one if you need to preserve camera metadata or colour profiles. If your use case needs different settings, you are looking at customizing the chain rather than passing an option to optimize().

## Compared with a pure-PHP or service-based approach

The natural alternative is a library that compresses inside the PHP process rather than shelling out. Those implementations re-encode through GD or Imagick and apply their own quantization, which removes the system package dependency entirely. The trade-off is real: you get a single composer require with nothing to install on the host, but you inherit that library's own compressor instead of the mature, widely deployed upstream tools. jpegoptim, pngquant and optipng have years of tuning behind them that a userland PHP compressor generally does not match.

The other alternative is an external service or a CDN that optimizes on delivery. That moves the work off your servers and out of your deploy, and it changes the failure mode from "binary missing" to "network and vendor dependency". It also means the optimized bytes may never exist on your disk, which matters if you serve the same asset outside the CDN path.

spatie/image-optimizer sits in the middle: it needs host-level packages, but it keeps the work local and the output on disk. The README also points to framework-specific wrappers, including a Laravel integration and a WP CLI command, which are worth knowing about if you are not writing the call yourself. Those are separate projects with their own release cycles, not part of this package.

## Maintenance, licence and what upgrades cost you

The repository is not archived and the last push was on 2026-06-29, the same day as the 1.10.0 release. That is recent enough that the project should not be described as abandoned, but the release history is worth reading before you plan an upgrade path: 1.8.1 landed on 2025-11-26, then 1.9.0 on 2026-06-25, then 1.10.0 four days later. Releases cluster rather than trickle, which is normal for a package whose surface area is mostly the option strings passed to external tools.

The licence is MIT, which permits commercial use, modification and redistribution provided the copyright notice and permission notice are retained. That is the standard permissive position and it is compatible with closed-source applications. This is a description of the licence text, not legal advice; if your organization has specific obligations around bundled dependencies, have counsel read the LICENSE file.

The ongoing cost is not the PHP package, it is the binaries. Their versions are outside the package's control. The README already pins a floor for one of them (libavif-bin minimum 0.9.3), and the option flags it passes to cwebp and avifenc depend on those tools accepting them. When you rebuild a base image or move to a newer distribution, the installed versions change and the compression results change with them. That is the upgrade surface to watch, not the composer.json entry.

## Conclusion

Adopt spatie/image-optimizer if you run PHP on a host where you control the system packages and you want a single optimize() call over a chain of well known binaries. Do not adopt it if you cannot install jpegoptim, pngquant, optipng, gifsicle, cwebp and avifenc, because the package ships no compression code of its own, or if you need to keep the original file intact, since optimize() overwrites the path you pass in. Before wiring it into an upload flow, check which binaries are actually present on the target machine and confirm the quality settings the README documents for each format against your own acceptance criteria.

## FAQ

### Is spatie/image-optimizer free?

Yes. The package is released under the MIT licence, which allows commercial and private use. The external binaries it calls have their own licences, so check those separately if you redistribute them.

### What is spatie/image-optimizer?

It is a PHP package that optimizes PNG, JPG, WEBP, AVIF, SVG and GIF files by running them through a chain of external command line tools. It detects which of those binaries are installed and uses them.

### Which image optimizer is the best?

There is no single answer, and this package does not claim to be one. It delegates to JpegOptim, Pngquant 2, Optipng, SVGO, Gifsicle, cwebp and avifenc, so its output quality is those tools' output quality under the option flags the README documents.

### Does compressing a JPEG reduce quality?

The README documents that JPGs are stored with JpegOptim at 85 percent quality, which is a lossy setting. It also passes --strip-all, which removes comments and EXIF data from the file.

## Sources

- [License: MIT](https://github.com/spatie/image-optimizer/blob/main/LICENSE)
- [Project website](https://freek.dev/797-easily-optimize-images-using-php-and-some-binaries)
- [README](https://github.com/spatie/image-optimizer/blob/main/README.md)
- [Releases](https://github.com/spatie/image-optimizer/releases)
- [spatie/image-optimizer on GitHub](https://github.com/spatie/image-optimizer)

---

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