Skip to content

Migrate from mPDF to NextPDF

This guide helps you move an mPDF-based codebase to NextPDF core. In mPDF, the main content call is WriteHTML(), which maps directly to Document::writeHtml(). Most of the work is the constructor config-array map (mPDF configures everything through one associative array passed to new Mpdf([...])) and the font-handling delta. NextPDF and mPDF are independent engines, so a migrated document is compatible with the mPDF output, not byte-identical to it. This guide covers the verb map, the config-array map, the font delta, the Cascading Style Sheets (CSS) support delta, the behavioral differences, and a safe sequence.

The Cascading Style Sheets (CSS) support matrix defines which Hypertext Markup Language (HTML) and CSS features are Verified. This guide describes behavior; it does not assert visual equivalence with mPDF.

Terminal window
composer require nextpdf/core:^3

Keep mpdf/mpdf installed while you migrate. Remove it after the final cutover (see safe migration sequence).

mPDF’s Mpdf object combines configuration and rendering behind one interface. A constructor array configures it, and WriteHTML() plus the paging verbs (AddPage, SetHTMLHeader, SetHTMLFooter) drive it. NextPDF separates configuration into the immutable NextPDF\Core\Config value object and writes content with Document::writeHtml(). There is no constructor “mode” string. NextPDF parses the HTML you pass, then emits the document with save(), output(), or getPdfData().

Fonts: mPDF ships with a font directory, a fontdata map, and a “core fonts” fallback set. NextPDF resolves fonts from one fonts directory plus CSS font-family matching, and always subsets embedded fonts (International Organization for Standardization (ISO) 32000-2 §9, iso32000_2_sec9#x1.x45.p7). Font matching and fallback are engine-specific (CSS Fonts 4 §5.5, css_fonts_4#x1.x5.x5.x1.p13), so glyph substitution can differ. This is the main visible delta, covered in the font-handling delta.

NextPDF’s HTML API is documented in the Html module reference. The core entry points are Document::createStandalone(), Document::writeHtml(string $html): static, Document::writeHtmlCell(...), Document::addPage(), Document::output(?string, OutputDestination), Document::save(string $path): void, Document::getPdfData(): string, and the NextPDF\Core\Config value object.

The mPDF public method names below are confirmed against the upstream public repository (mpdf/mpdf, development); see the in-repo _source-sidecar-upstream-api.md provenance sidecar. No upstream documentation text is reproduced.

mPDFNextPDFNotes
new Mpdf([...])Document::createStandalone($config)The mPDF config array maps to NextPDF\Core\Config; see config map. Use DocumentFactory for long-lived workers.
$mpdf->WriteHTML($html)$doc->writeHtml($html)Direct map. mPDF’s second $mode argument (full document vs. CSS-only vs. element) has no NextPDF analogue; pass complete HTML.
$mpdf->WriteFixedPosHTML(...)$doc->writeHtmlCell(...)Positioned and sized HTML region; map x/y/width/height arguments.
$mpdf->AddPage(...)$doc->addPage()NextPDF does not take mPDF’s per-call orientation/format/margin overrides as arguments; change the document model between calls instead.
$mpdf->SetHTMLHeader($html) / SetHTMLFooter($html)header/footer via the Layout APImPDF running HTML headers map to the NextPDF header/footer mechanism, not to inline HTML at the top of the body.
$mpdf->Output($name, $dest)$doc->output($name, OutputDestination::…)mPDF destination characters (I/D/F/S) map to the OutputDestination enum (Inline/Download/file via save()/string via getPdfData()).
$mpdf->Output('','S')$doc->getPdfData()Returns bytes.
$mpdf->Output($path,'F')$doc->save($path)Writes to a file path.
$mpdf->SetTitle($t)$doc->setTitle($t)Lands in the ISO 32000-2 §14 information dictionary / Extensible Metadata Platform (XMP) (iso32000_2_sec14#x1.x5.p5).
$mpdf->SetProtection($perms,...)$doc->setEncryption(...) (Security API)Permissions are reader-cooperative, not access control — see Security notes.
<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;
// mPDF:
// $mpdf = new \Mpdf\Mpdf();
// $mpdf->WriteHTML('<h1>Invoice</h1>');
// $mpdf->Output('out.pdf', \Mpdf\Output\Destination::FILE);
// NextPDF — default page is A4 portrait:
$doc = Document::createStandalone();
$doc->setTitle('Invoice');
$doc->addPage();
$doc->writeHtml('<h1>Invoice</h1>');
$doc->save(__DIR__ . '/out.pdf');
echo "Wrote out.pdf\n";

This example aligns with examples/04-text-and-fonts.php, the runnable backing for the font-handling concepts in this guide. It uses an explicit page size, margins, and a content body that exercises font selection.

<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Contracts\OutputDestination;
use NextPDF\Core\Config;
use NextPDF\Core\Document;
use NextPDF\ValueObjects\Margin;
use NextPDF\ValueObjects\PageSize;
// Equivalent of: new Mpdf(['format'=>'A4','margin_left'=>20, ...]).
// Margin constructor order is (top, right, bottom, left) — NOT L,R,T,B.
$config = new Config(
pageSize: new PageSize(595.276, 841.890, 'A4'),
margins: new Margin(16.0, 20.0, 16.0, 20.0), // top,right,bottom,left in points
fontsDirectory: __DIR__ . '/fonts',
);
$doc = Document::createStandalone($config);
$doc->setTitle('Quarterly Report');
$doc->addPage();
$html = <<<'HTML'
<h1 style="font-family:'DejaVu Sans';color:#1E3A8A;">Quarterly Report</h1>
<p>Body text resolves through CSS font-family matching against the configured
fonts directory. mPDF's fontdata map has no direct analogue — register the
family via CSS and the fonts directory instead.</p>
HTML;
$doc->writeHtml($html);
// Equivalent of $mpdf->Output('report.pdf', Destination::DOWNLOAD):
$doc->output('report.pdf', OutputDestination::Download);
  • $mode argument on WriteHTML. mPDF’s WriteHTML($html, $mode) (2 = CSS only, 1 = element) has no equivalent. Put CSS in the HTML you pass; there is no “write CSS then write body” sequence.
  • Per-AddPage overrides. mPDF lets AddPage() change format/orientation mid-document with arguments. NextPDF addPage() takes no such arguments; model size changes through the document, not the page call.
  • Header/footer HTML. mPDF registers running headers as separate HTML fragments; do not paste them into the body. Map them to the NextPDF header/footer mechanism.
  • Font names. mPDF normalizes font names through its fontdata/core-font table. NextPDF matches the CSS font-family against the fonts directory; an mPDF alias that resolved silently may need an explicit @font-face/family.
  • Destination characters. 'I'/'D'/'F'/'S' are not accepted; use the OutputDestination enum or save()/getPdfData().

writeHtml() is single-pass (ADR-001); peak memory tracks document size, not a retained Document Object Model (DOM). Budget for this guide’s example: wall_ms: 2000, peak_mb: 128. For long documents, split content across addPage() calls rather than passing one giant string. This is the same guidance that applies to mPDF’s $mode chunking, expressed through the page model.

  • Permissions are reader-cooperative. SetProtection()setEncryption() provides confidentiality, not access control: ISO permission bits depend on a cooperating reader. Do not present encryption as access control to users.
  • Metadata. SetTitle() and document information land in the ISO 32000-2 §14 information dictionary / XMP (iso32000_2_sec14#x1.x5.p5); never store secrets there.
  • NextPDF does not execute in-document scripts; no mPDF directive changes that here.
StatementSpecClausereference_id
Fonts are written as embedded/subset font programs.ISO 32000-2§9
Page format/margins map to the page boundary box.ISO 32000-2§7
Title / protection metadata land in the info dictionary / XMP.ISO 32000-2§14
Font matching / fallback is engine-specific.CSS Fonts 4§5.5

NextPDF produces ISO 32000-2 content; it does not assert visual identity with mPDF. Re-review output whenever you change renderer.

Not applicable. NextPDF core covers the mPDF migration path described here.


Teams running mpdf/mpdf for server-side HTML-to-PDF. If your code is built around new Mpdf([...]) + WriteHTML + Output (+ optional header/footer), the verb mapping and config map cover it.

In scope: the Mpdf constructor config array, WriteHTML/Output/AddPage, headers/footers, fonts, protection, metadata. Out of scope: mPDF internal classes and the Quick Response (QR)/barcode/watermark helper surface. Map those to the corresponding NextPDF modules — Barcode, Graphics — which are not covered here.

Behavioral compatibility, not a drop-in shim: NextPDF does not provide an Mpdf class shim. Rewrite every call site. Use the CSS support matrix Verified rows for CSS-feature expectations.

The mPDF config keys below are confirmed against the upstream public repository (mpdf/mpdf, development). No upstream documentation text is reproduced.

mPDF config keyNextPDFNotes
mode(no equivalent)mPDF’s mode string ('utf-8', 'c', '+aCJK', …) selects font/script behavior. NextPDF is always Unicode; Chinese, Japanese, and Korean (CJK) text is handled by font selection, not a mode. Drop the key.
formatConfig->pageSize (PageSize value object (VO))Named formats become explicit point dimensions; arrays [w,h] map to a PageSize.
orientationswap PageSize width/heightNo orientation flag; landscape means width > height.
default_font_sizeCSS base font-sizeSet this in your base stylesheet, not a constructor key.
default_fontCSS font-family / registered fontSet the default family through CSS / font registration.
margin_left / margin_right / margin_top / margin_bottomConfig->margins (Margin VO) in pointsUse one Margin value object; its constructor order is Margin(top, right, bottom, left) (verify against src/ValueObjects/Margin.php), not the mPDF key order.
margin_header / margin_footerheader/footer offset via Layout APIMap these to the NextPDF header/footer configuration, not constructor keys.
  • Single fonts directory. mPDF’s font directory list, fontdata map, and core-font fallback collapse to Config->fontsDirectory plus CSS font-family matching.
  • Always subset. NextPDF always subsets embedded fonts (ISO 32000-2 §9, iso32000_2_sec9#x1.x45.p7); mPDF’s subset flags have no equivalent and are not needed.
  • Matching is engine-specific. Font matching and fallback differ by engine (CSS Fonts 4 §5.5, css_fonts_4#x1.x5.x5.x1.p13); an mPDF font alias may need an explicit @font-face or exact family name. Re-baseline glyph rendering after migration. Substitution differences are expected, not defects.
  • Font substitution (see above) — the main visible delta.
  • No $mode on WriteHTML — pass complete HTML with inline CSS.
  • No per-AddPage format override — model size changes through the document.
  • Permissions are reader-cooperative (see Security notes).
  • Independent layout engine — line wrap / pagination differs on dense content; re-baseline visual diffs.

These are documented behavioral differences, not defects in either engine.

  • mode constructor string — not modeled (always Unicode).
  • Per-AddPage() format/orientation/margin arguments — not arguments in NextPDF.
  • mPDF fontdata map — replaced by fonts directory + CSS matching.
  • mPDF’s 'I'/'D'/'F'/'S' destination chars — replaced by the OutputDestination enum + save()/getPdfData().
  1. Add nextpdf/core alongside mpdf/mpdf; keep mPDF installed for now.
  2. Choose one low-risk document. Convert new Mpdf([...]) via the config map and WriteHTML/Output via the verb map.
  3. Register the fonts the document uses in Config->fontsDirectory, and add explicit @font-face/family declarations for any mPDF alias.
  4. Generate both PDFs for the same input and visually diff them. Differences (font substitution, line wrap) are expected for independent engines — accept them per document.
  5. Map any header/footer HTML to the NextPDF header/footer mechanism.
  6. Repeat per document, lowest risk first; keep mPDF installed until the last cutover.
  7. Remove mpdf/mpdf from composer.json after the final cutover.
  • Snapshot mPDF output for representative documents before you change code (golden inputs; the bytes will differ).
  • For each migrated document, assert acceptance with your own check (visual diff
    • text-extraction). NextPDF’s font/HTML behavior is exercised by examples/04-text-and-fonts.php and examples/08-html-basic.php plus the core tests/ Html/Font suites. Migration acceptance is document-specific and remains your responsibility.
  • Add a regression test per migrated document.

Every NextPDF behavioral statement on this page is backed by an in-repo test, example, source signature, or architecture decision record (ADR), or, for PDF-format properties, by the retrieval-augmented generation (RAG)-pinned ISO 32000-2 / CSS clauses in the front-matter citations: and the Conformance table. mPDF behavior is asserted only as “independent engine — expect documented differences”; this page claims no parity that an in-repo artifact does not prove.

NextPDF behavioral claimIn-repo evidence (path)
WriteHTML() maps directly to Document::writeHtml(string $html): static.src/Core/Concerns/HasTextOutput.php (writeHtml()); examples/08-html-basic.php.
WriteFixedPosHTML(...) maps to writeHtmlCell(...).src/Core/Concerns/HasTextOutput.php (writeHtmlCell()).
createStandalone() default page is A4 portrait (595.276 × 841.890 pt).src/Core/Config.php (default PageSize); tests/Unit/Core/DocumentCreateStandaloneAndConfigWithersEdgeCaseTest.php.
Margin constructor order is (top, right, bottom, left).src/ValueObjects/Margin.php (promoted-property order).
Output destination is the NextPDF\Contracts\OutputDestination enum; 'I'/'D'/'F'/'S' are not accepted.src/Contracts/OutputDestination.php (cases Inline/Download/File/String); tests/Unit/Core/Concerns/DocumentOutputDestinationDispatchTest.php.
Output('','S')getPdfData(); Output($path,'F')save($path).src/Core/Concerns/HasOutput.php (getPdfData(), save(), output()).
SetProtection() maps to setEncryption(...); permissions are reader-cooperative.src/Core/Concerns/HasSecurity.php (setEncryption()); ISO 32000-2 §14 (front-matter citations:).
SetTitle()setTitle(); metadata lands in the info dictionary / XMP.src/Core/Concerns/HasMetadata.php (setTitle()); tests/Unit/Core/Concerns/DocumentInfoMetadataSetterBaselineTest.php; ISO 32000-2 §14 (front-matter citations:).
Fonts are always embedded as subset programs.tests/Unit/Core/Concerns/DocumentTextOutputFontSubsettingAndBorderEdgeCaseTest.php; examples/04-text-and-fonts.php; ISO 32000-2 §9 (front-matter citations:).
Font matching / fallback is engine-specific (substitution delta).CSS Fonts 4 §5.5 (front-matter citations: + Conformance).
writeHtml() is single-pass; peak memory tracks document size.docs/architecture/adr/ADR-001-stream-based-rendering-pipeline.md.

Both packages stay installed until the final cutover, so per-call-site rollback means reverting that call site to the mPDF path. After the final cutover, rollback means restoring mpdf/mpdf and the prior code from version control. No data migration is involved.

See Performance. The single-pass model removes mPDF’s retained buffer cost. The new per-document cost is eager font resolution (step 3), which is cacheable through the fonts directory.

  • Keeping the mode key and expecting CJK behavior from it; NextPDF drops it, and CJK is font selection.
  • Passing WriteHTML($html, 2) (CSS-only mode); inline CSS instead.
  • Pasting header/footer HTML into the body.
  • Expecting an mPDF alias to resolve to the same font without an explicit family.
  • Expecting byte/pixel-identical output (independent engines — this guide never claims a drop-in or 100% compatibility).
  • Treating the CSS support matrix as advisory; it is the Verified-feature authority.