Generate PDF files with PeachPDF

Our second recommended HTML-to-PDF library: pure .NET, BSD licensed, with system fonts, SVG and MathML - no Chrome needed.

PeachPDF is the second HTML-to-PDF library we recommend, next to PdfPecker. Like PdfPecker it is pure .NET and runs inside your application, so it does not start Chrome and works on the Free and Premium plans alike. Headless browsers (Puppeteer, Playwright, Selenium) are not allowed on the Free plan and on Premium need an exception from our security system; with one of these two libraries you do not need a browser at all.

Our first choice is PdfPecker. Pick PeachPDF when one of its strengths matters to you: it uses the fonts installed on the server automatically, draws SVG and MathML as vectors, reads AVIF and JPEG XL images, has a large community and a permissive BSD license.

Why PeachPDF

PeachPDF Headless Chrome (Puppeteer, Playwright)
How it works Managed .NET packages (about 9 MB of DLLs) loaded into your application Downloads and starts a separate Chrome browser (about 600 MB)
Free plan Works Not allowed — the website is suspended by the security system
Premium plan Works Allowed after an exception requested through a support ticket
Dependencies Only managed NuGet packages; no native binaries, no browser Chrome binaries, their updates, a browser pool to manage
Memory Stays inside your application 800 MB to 1 GB — usually more than the memory limit of a website
Deployment NuGet packages only, nothing to install on the server Browser binaries downloaded into the website folder at start-up

What else makes it a good fit:

  • Modern CSS. Flexbox, grid with subgrid, multi-column layout, container queries, cascade layers, custom properties, gradients. Paged media with @page rules, margin boxes, running headers and footers, footnotes, bookmarks and CSS-driven tables of contents.
  • System fonts. The fonts installed on our Windows servers (Arial, Segoe UI, Calibri, Times New Roman and others) are found and embedded automatically; web fonts in @font-face (TrueType, CFF, WOFF, WOFF2) work too. Arabic and Indic shaping, bidirectional text and color emoji are supported.
  • Vector graphics. SVG and MathML are drawn as true vector content, never rasterised.
  • Images. JPEG, PNG, GIF, BMP, WebP, AVIF, TIFF and JPEG XL.
  • Standards. Tagged PDF (PDF/UA), PDF/A-1 to 3, PDF/X-1a/3/4, PDF 2.0, encryption, Factur-X e-invoices, attachments. PDF metadata is taken from <title> and <meta> tags.
  • Forms. <input> and <select> can become fillable AcroForm fields (EnableInteractivePdfForms).
  • More than conversion. A declarative C# API in the style of QuestPDF, and PDF merging, splitting and protection through the PeachDrawing.PDF package.
  • BSD 3-Clause license, source on GitHub, targets .NET 8 and newer, trimming and Native AOT compatible.

Note

PeachPDF is a document engine, not a web browser. <script> tags are ignored, so a page that builds its content with JavaScript in the browser must be rendered on the server first (a Razor view, a template engine, a string builder). Converting a live website or taking screenshots still needs Chrome and the Premium plan.

Install the package

dotnet add package PeachPDF

Or in Visual Studio: Manage NuGet Packages → search for PeachPDF → Install. No further set-up is needed on your computer or on the server.

A simple test

  1. Create a project

    Create an ASP.NET Core Empty project (.NET 8 or newer) and install the PeachPDF package.

  2. Replace Program.cs

    The application converts a small invoice to PDF and returns it on /invoice. The page size and the footer with page numbers come from the @page rule in the CSS:

    using PeachPDF;
    
    var builder = WebApplication.CreateBuilder(args);
    var app = builder.Build();
    
    string html = """
    <!DOCTYPE html>
    <html>
    <head>
      <title>Invoice 2026-104</title>
      <style>
        @page {
          size: A4;
          margin: 20mm 15mm;
          @bottom-center { content: "Page " counter(page) " of " counter(pages); font-size: 9pt; color: #888; }
        }
        body { font-family: Arial, sans-serif; }
        h1 { color: #2563eb; }
        table { width: 100%; border-collapse: collapse; margin-top: 16px; }
        th, td { border: 1px solid #ccc; padding: 6px 8px; text-align: left; }
        th { background: #f1f5f9; }
        td.num { text-align: right; }
      </style>
    </head>
    <body>
      <h1>Invoice 2026-104</h1>
      <p>Billed to: Example Ltd., Prague</p>
      <table>
        <tr><th>Item</th><th>Qty</th><th>Price</th></tr>
        <tr><td>Premium hosting</td><td class="num">1</td><td class="num">120.00</td></tr>
        <tr><td>Extra storage</td><td class="num">2</td><td class="num">10.00</td></tr>
      </table>
    </body>
    </html>
    """;
    
    var config = new PdfGenerateConfig
    {
        PageSize = PageSize.A4,
        PageOrientation = PageOrientation.Portrait,
    };
    
    app.MapGet("/invoice", async () =>
    {
        var generator = new PdfGenerator();        // one instance per request - it is not thread-safe
        var document = await generator.GeneratePdf(html, config);
    
        var stream = new MemoryStream();
        document.Save(stream);
        stream.Position = 0;
    
        return Results.File(stream, "application/pdf", "invoice.pdf");
    });
    
    app.Run();
    
  3. Publish and open

    Publish the project to your website — see Deploy from Visual Studio — and open https://yourdomain.com/invoice. The browser downloads a one-page PDF with the invoice table and Page 1 of 1 in the footer.

In an MVC controller the ending is the same: render the view to a string, generate the document and return File(stream, "application/pdf", "invoice.pdf"). To save the PDF to disk, pass a FileStream to document.Save().

Important

A PdfGenerator instance is not thread-safe. Create a new one for every request or task; do not keep one in a static field or a singleton service. PdfGenerateConfig can be shared.

Page size, margins and metadata

The CSS @page rule is the simplest way to set the page size, margins and running headers or footers, as in the example above. The same can be set in code through PdfGenerateConfig: PageSize, PageOrientation, MarginTop, MarginRight, MarginBottom and MarginLeft. The PDF title, author, subject and keywords are taken from <title> and <meta name="author">, subject, keywords in the HTML. For archiving set PdfAConformance, for accessibility EnableTaggedPdf = true.

Images, stylesheets and fonts

  • Files on the server. An <img> or <link rel="stylesheet"> with an absolute path (D:\... or file:///D:/...) is read from disk. For relative paths pass a FileUriNetworkLoader pointing at the folder of your templates:

    var config = new PdfGenerateConfig
    {
        NetworkLoader = new PeachPDF.Network.FileUriNetworkLoader(
            Path.Combine(app.Environment.WebRootPath, "templates", "invoice.html")),
    };
    

    Do not rely on relative paths without a loader: they resolve against the working directory of the process, which is not your wwwroot on the server.

  • Data URIs. <img src="data:image/png;base64,..."> works in <img> tags and in CSS backgrounds.

  • Remote URLs. Pass an HttpClientNetworkLoader with your own HttpClient; the loader then fetches the root document and every stylesheet and image it references over HTTP.

  • Fonts. Installed server fonts are used automatically, so font-family: Arial just works. A font that is not installed on the server can be shipped with the application and registered at run time:

    using var fontStream = File.OpenRead(Path.Combine(app.Environment.WebRootPath, "fonts", "OpenSans-Regular.ttf"));
    await generator.AddFontFromStream(fontStream);   // TrueType, CFF, WOFF and WOFF2
    

Limitations

  • No JavaScript; <iframe> is drawn as a placeholder box, <video> shows only its poster image.
  • Effects a PDF cannot express (filter: blur(), backdrop-filter, 3D perspective) are rasterised or skipped.
  • The library is pre-1.0 (version 0.9.x); minor versions can contain breaking changes, so pin the package version and read the release notes before updating.
  • The package targets .NET 8 and newer. For an application on .NET Framework 4.x use a managed library such as PdfSharp or QuestPDF, or move the PDF generation into a small .NET 8+ website.

The full compatibility matrix is on the vendor's HTML & CSS support page, more code in Usage examples.

Still stuck? Our support team is happy to help.
Ask the community Open a support ticket