Swevo.FluentPdf

A free, MIT-licensed fluent PDF generation library for .NET. Compose invoices, reports, and multi-page documents with a declarative API, automatic pagination for text and tables, and no revenue-based licensing.


Keywords
csharp, document, dotnet, fluent, invoice, pdf, pdf-generation, reporting
License
MIT
Install
Install-Package Swevo.FluentPdf -Version 1.2.1

Documentation

FluentPdf

NuGet NuGet Downloads CI License: MIT

Free, MIT-licensed fluent PDF generation for .NET. No revenue threshold, no commercial license — ever.

Why FluentPdf?

QuestPDF's Community License (v3.0, effective July 2026) is free only for individuals, academia, charities, and businesses under $1M annual revenue — public companies and government agencies don't qualify at any revenue. If your product grows, or you're a public-sector team, you need a paid QuestPDF license. FluentPdf uses the same declarative, fluent building-block style but is MIT-licensed for everyone, regardless of revenue or company type.

Document.Create(container =>
{
    container.Page(page =>
    {
        page.Size(PageSizes.A4);
        page.Margin(40);

        page.Header().Text("Invoice #1042").FontSize(20).Bold();

        page.Content().Column(column =>
        {
            column.Item().Text("Bill to: Acme Corp");
            column.Item().Padding(0, 10, 0, 0).Table(table =>
            {
                table.ColumnsDefinition(columns =>
                {
                    columns.RelativeColumn(3);
                    columns.RelativeColumn(1);
                });
                table.HeaderCell().Text("Item").Bold();
                table.HeaderCell().Text("Price").Bold();

                foreach (var line in invoiceLines)
                {
                    table.Cell().Text(line.Name);
                    table.Cell().Text(line.Price.ToString("C"));
                }
            });
        });

        page.Footer().AlignCenter().Text(x => $"Page {x}");
    });
}).GeneratePdf("invoice.pdf");

Install

dotnet add package Swevo.FluentPdf

FluentPdf is built on PdfSharp (MIT-licensed) for low-level PDF drawing, with its own layout/pagination engine on top.

Linux font setup

PdfSharp has no bundled fonts and Linux containers often ship without any TrueType fonts at all. FluentPdf automatically scans common OS font directories (/usr/share/fonts, /usr/local/share/fonts, the Windows Fonts folder, macOS's /System/Library/Fonts) and picks the first match from DejaVu Sans, Liberation Sans, Noto Sans, Arial, Segoe UI, or Helvetica. On a bare Linux image (e.g. a minimal Docker base or a fresh GitHub Actions runner), install one:

apt-get install -y fonts-dejavu-core

Or register your own font explicitly, bypassing OS discovery entirely:

FluentPdfFonts.RegisterFont(
    "Roboto",
    regular: File.ReadAllBytes("fonts/Roboto-Regular.ttf"),
    bold: File.ReadAllBytes("fonts/Roboto-Bold.ttf"));

Core concepts

  • Document.Create(...) — top-level entry point; add one or more Page templates.
  • page.Header() / page.Content() / page.Footer() — Header and Footer are fixed-height and rendered fully on every page; Content is automatically paginated across as many pages as needed.
  • Column / Row — vertical/horizontal layout containers; Row items use relative (weighted) widths.
  • Table — relative-width columns with an optional repeating header row; splits at row boundaries across pages.
  • Text — automatic word-wrapping; splits mid-paragraph across pages if needed. Text(x => $"Page {x}") (inside Header/Footer only) renders the current page number.
  • Decorators.Padding(...), .Background(color), .Border(thickness, color), .AlignCenter() / .AlignRight() wrap whatever comes next in the chain.

Pagination model

Every layout node knows how to measure itself and render as much of itself as fits in the remaining space, handing back a "continuation" for whatever didn't fit. Text and Table split mid-content (mid-line, mid-row); Row, Border, and Align move as a whole block to the next page if they don't fit (documented below as current limitations).

Known limitations (v1.0)

  • Row, Border, and Align are non-splittable — they move wholesale to the next page rather than splitting internally. Column and Table are the primary paginated containers.
  • No image support yet.
  • No cell-level borders/backgrounds inside Table (wrap individual cells with .Border() / .Background() as a workaround).

Contributions and issues for any of the above are welcome.

Design goals

  • MIT licensed, forever. No commercial tier, no revenue threshold.
  • Small, understandable engine. A handful of composable IElement nodes rather than a large proprietary layout DSL.
  • Works out of the box on Linux CI, given a system font is installed.

💼 Need .NET consulting?

I'm the author of FluentPdf and a suite of compile-time source generators (AutoWire, AutoMap.Generator) and 28+ Polly v8 resilience packages. I'm available for consulting on Polly v8 resilience, Azure cloud architecture, and clean .NET design.

→ solidqualitysolutions.com · LinkedIn

Also by the same author

🌐 Full suite overview: swevo.github.io

Package Description
AutoBus Free, MIT-licensed message bus — alternative to MassTransit's commercial license.
AutoArchitecture Free, MIT-licensed compile-time architecture rule enforcement — alternative to NDepend.
EFCore.Outbox Transactional outbox pattern for EF Core.
Swevo.AutoAssert Free, MIT-licensed fluent assertions — alternative to FluentAssertions' commercial license.
EFCore.BulkOperations Free, MIT-licensed bulk insert/update/delete for EF Core.
AutoWire Compile-time DI auto-registration.
AutoDispatch.Generator Compile-time CQRS dispatcher — free alternative to MediatR's commercial license.
PollyAnalyzers Free Roslyn analyzers for async/resilience anti-patterns — blocking calls, async void, fire-and-forget tasks, swallowed exceptions.
PollyAction Free retry/backoff GitHub Action — wrap any CI step with exponential-backoff retries.

License

MIT © Justin Bannister