# mPDF: a PHP library that turns UTF-8 HTML into PDF files

> mPDF renders HTML and CSS to PDF from inside a PHP process, which makes it a fit for server-side invoices and CJK documents and a poor fit for pixel-perfect web page mirroring. The README is candid that the CSS engine is dated.

**mpdf/mpdf** — PHP library generating PDF files from UTF-8 encoded HTML

- Repository: https://github.com/mpdf/mpdf
- Website: https://mpdf.github.io
- Stars: 4,704 · Forks: 1,108
- Language: PHP
- License: GPL-2.0
- Published: 2026-09-23 · Updated: 2026-09-23 · Language: en
- Canonical page: https://hysenlabs.com/projects/mpdf-mpdf

## What mPDF does that a browser print dialog does not

mPDF is a PHP library that generates PDF files from UTF-8 encoded HTML. That sentence is the whole product. The interesting part is where it runs: inside your PHP process, with no browser, no headless Chrome binary and no external rendering service. You hand it a string of HTML, it hands you bytes.

The README is explicit about the audience. mPDF is based on FPDF and HTML2FPDF with enhancements, and it was written by Ian Back. The cases it names for itself are colour handling, pre-print, barcode support, headers and footers, page numbering and tables of contents. Those are document features, not web page features. A table of contents that resolves page numbers only makes sense if the renderer knows the pagination, which a browser print pipeline generally does not expose to you.

So the target user is a PHP developer producing a document: an invoice, a statement, a shipping label, a certificate with a barcode, a report with running headers. The target user is not someone trying to archive a marketing page as a PDF, and the README says so directly when it recommends headless Chrome for that job.

## How the HTML-to-PDF pipeline is put together

The architecture is visible in the repository layout rather than in prose. There is src/, which holds the library, and ttfonts/, which holds TrueType fonts. The presence of a font directory at the top level tells you something important: mPDF does not rely on system fonts. It ships fonts and embeds subsets of them into the output, which is what makes CJK output and consistent typography possible on a server that has no font stack configured.

That also explains the optional extensions. The README lists mbstring and gd as required, then names zlib for compression of output and embedded resources such as fonts, bcmath for generating barcodes, and xml for character set conversion and SVG handling. Each of those maps to a stage: parse the HTML, lay out text with the bundled metrics, draw any barcode or SVG, compress the result, write the PDF. If zlib is missing you still get a PDF, just a larger one.

The data flow is stateful. You construct an Mpdf object, call WriteHTML one or more times, then call Output. Because the object accumulates pages, you can write a header block, then a body, then a footer, and the renderer paginates as it goes. Configuration is not a separate config file: the README states that all configuration directives can be set through the $config parameter of the constructor.

## Installing mPDF with Composer and rendering a first document

The README names Composer as the official installation method, through the Packagist package mpdf/mpdf. There is no separate download step in the documented path.

```bash
$ composer require mpdf/mpdf
```

After that, the simplest usage since version 7.0 is three calls: autoload, construct, write, output. The README gives this exact example.

```php
<?php

require_once __DIR__ . '/vendor/autoload.php';

$mpdf = new \Mpdf\Mpdf();
$mpdf->WriteHTML('<h1>Hello world!</h1>');
$mpdf->Output();
```

The README states that Output with no arguments sends the PDF inline to the browser with an application/pdf content type. If you are running this from a CLI script rather than a web request, expect the bytes to go to standard output instead.

Before you use this in production, set your own temporary directory. The README recommends it, because mPDF will clean up old temporary files in that directory and you do not want it cleaning a shared path. The constructor takes it directly.

```php
<?php

$mpdf = new \Mpdf\Mpdf(['tempDir' => __DIR__ . '/tmp']);
```

The README says the directory must be writable by the users running mPDF, typically cli, webserver and fpm, and suggests mode 775. It also warns that the path should be dedicated to mPDF only. By default the temporary directory sits inside the vendor directory and gets write permissions from a post_install Composer script, which works until a deploy resets permissions.

One caveat the README calls out for local development: mPDF has problems fetching external HTTP resources with single threaded servers such as php -S. A proper server such as nginx with php-fpm, or Apache, is recommended.

## The CSS engine is dated, and the README says so

This is the limitation that decides most adoption questions, and it is unusual to see a project state it this plainly. The README calls mPDF as a whole quite dated software, notes that better alternatives exist though not written in PHP, and says that better or newer CSS support will most likely not be implemented. The stated maintenance direction is internal capabilities and support for newer PHP versions.

The practical consequence is that an HTML/CSS template tailored for mPDF might be necessary. You cannot take the stylesheet from your web application and expect the same result. Modern layout mechanisms are not part of the promise, and the project is not planning to add them.

There is a second, quieter failure mode in the same area. Because mPDF fetches external resources in some paths, a template that references a remote stylesheet or image behaves differently depending on the server it runs on. The README's note about single threaded servers is the documented symptom; the underlying issue is that rendering can depend on outbound HTTP, which is a poor property for a document generator that you want to be deterministic.

Finally, the default branch is development, and the README warns that it can differ from the last stable release. If you vendor mPDF from a branch rather than a tagged release, you are testing unreleased code.

## mPDF against headless Chrome, and against staying in PHP

The README names headless Chrome as the alternative, and the difference is not cosmetic. A browser renderer reuses the CSS engine you already target, so one template serves both the web page and the PDF. mPDF reimplements layout in PHP and its own CSS handling, so you maintain a second template. That is the cost you pay for not running a browser.

What you get back is the PHP-process property. There is no Chrome binary to install, no separate rendering service, no IPC boundary, and no version skew between the browser on your laptop and the one in the container. The README's list of features that justify the trade is concrete: colour handling, pre-print, barcodes, headers and footers, page numbering, tables of contents. A browser print pipeline gives you headers and footers through print CSS, but page numbering and TOC generation with resolved page references are the kind of thing you would otherwise build yourself from a PDF library.

The honest framing is that these are two different products. If your requirement is that the PDF look like the page, use a browser. If your requirement is that the PDF be produced by a PHP worker with no extra runtime, and that it carry document furniture, mPDF is the PHP-native answer.

## Licence, releases and what upgrading actually costs

mPDF is released under the GNU GPL v2 licence, and the licence file is LICENSE.txt in the repository root. This is not a permissive licence. If you distribute software that includes mPDF, the GPL terms attach to that distribution, and that is a decision for your legal team rather than something this article can settle. The README states the licence plainly; it does not offer a commercial alternative.

On releases, the pattern matters more than any single version. The last stable release listed is v8.1.0 from 2022-04-16, following v8.0.0 in 2019 and v7.1.0 in 2018. That is a slow release cadence for stable tags, and it is the reason the README's PHP support table is written per patch version rather than per major version: PHP 7.4 is supported since v8.0.4, PHP 8.0 since v8.0.10, PHP 8.1 since v8.0.13, PHP 8.2 since v8.1.3, PHP 8.3 since v8.2.1, PHP 8.4 since v8.2.5 and PHP 8.5 since v8.2.6. Those later patch releases are not in the release list above, so if you are on a current PHP version you are pulling a tag newer than the last listed stable release.

The repository is not archived and the last push was on 2026-09-08, so work is happening between releases. The upgrade cost you should budget for is not the Composer update. It is the template: when a patch release changes layout behaviour, the fix lands in your mPDF-specific HTML and CSS, which is the part of the codebase no other tool reads.

## Conclusion

Adopt mPDF when the PDF has to be produced inside a PHP request or worker and the document is a structured one (invoice, report, certificate, barcode label) rather than a mirror of a web page. Do not adopt it if your template is a modern CSS layout you also want to render in a browser, or if you cannot accept GPL-2.0 terms for the whole distribution. Before committing, verify three things against your own code: that your PHP version maps to a release the README lists as supported, that you can point tempDir at a directory dedicated to mPDF and writable by the web server user, and that your HTML survives a trial render without external HTTP resources if you run behind php -S.

## FAQ

### What is the latest version of mPDF?

The most recent stable release listed for the project is v8.1.0, dated 2022-04-16. The README's PHP support table references later patch versions such as v8.2.6 for PHP 8.5, so those tags exist beyond the listed stable release.

### How do I install mPDF?

The README names Composer as the official method, using the Packagist package mpdf/mpdf. Run composer require mpdf/mpdf and require the generated vendor/autoload.php in your script.

### What PHP extensions does mPDF require?

The README states that mbstring and gd have to be loaded. It adds that zlib is needed for compression of output and embedded resources such as fonts, bcmath for generating barcodes, and xml for character set conversion and SVG handling.

### Can mPDF render modern CSS layouts?

The README describes mPDF as quite dated software and says better or newer CSS support will most likely not be implemented. It warns that an HTML/CSS template tailored for mPDF might be necessary, and points to headless Chrome for mirroring existing HTML pages.

### Why does mPDF need a temporary directory?

The README recommends setting your own via the tempDir constructor variable, writable by the users running mPDF at mode 775. It warns that mPDF cleans up old temporary files there, so the path should be dedicated to mPDF only.

## Sources

- [License: GPL-2.0](https://github.com/mpdf/mpdf/blob/development/LICENSE)
- [mpdf/mpdf on GitHub](https://github.com/mpdf/mpdf)
- [Project website](https://mpdf.github.io)
- [README](https://github.com/mpdf/mpdf/blob/development/README.md)
- [Releases](https://github.com/mpdf/mpdf/releases)

---

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