Generate PDFs in C# Using QuestPDF: Complete Guide

PDF generation in .NET has always been a bit of a pain – absolute positioning, manual pagination, fiddly styling calculations. QuestPDF takes a different approach with a layout-based system and a fluent API that feels natural to C# developers. This guide walks through how QuestPDF handles PDF creation, from basic setup to building a full invoice with QR codes.
What is QuestPDF?
QuestPDF is an open-source, modern .NET library built specifically for programmatic PDF document creation. It provides a full-featured layout engine powered by a concise C# Fluent API that handles the complexities of document structure automatically.
Key Features and Capabilities
QuestPDF offers a wide set of features that distinguish it from other C# PDF generation libraries:
- Container-based layout system that eliminates the need for absolute positioning and coordinates.
- Automatic pagination with content overflow handling between pages.
- Dynamic data binding using standard C# patterns (loops, conditionals).
- Rich text formatting with full control over fonts, styles, and alignment.
- Responsive tables and grids with flexible column definitions.
- SVG and image support with multiple sizing options.
From invoices and reports to contracts and data exports, QuestPDF's layout approach cuts development time while producing polished documents.
This guide walks you through everything from basic setup to advanced techniques for implementing PDF document generation in your C#/.NET applications.
QuestPDF is not an HTML to PDF converter. It provides a programming interface for creating and manipulating PDF documents directly in C#.
If you're looking to convert HTML to PDF in C#, you'll need a separate tool or library such as DinkToPdf, PuppeteerSharp, or Playwright. See HTML to PDF Conversion Options for a full comparison.
Getting Started with QuestPDF in C#/.NET Projects
Installation
Add QuestPDF to your .NET project using one of the following methods:
Using the .NET CLI:
dotnet add package QuestPDF
Using the Package Manager Console:
Install-Package QuestPDF
You can also add a reference in your .csproj file:
<PackageReference Include="QuestPDF" Version="2025.12.4" />
Setting Up the License
QuestPDF offers a tiered licensing model:
- Community License: Free for individuals, non-profits, open-source projects, and businesses with annual revenue below $1M USD. Suitable for most use cases.
- Professional/Enterprise Licenses: Required for larger organizations.
Add this line at startup to set the license:
QuestPDF.Settings.License = LicenseType.Community;
// or LicenseType.Professional or LicenseType.Enterprise
For detailed licensing information, visit the QuestPDF License and Pricing page.
Our First PDF Document
Let's create a simple PDF with some text:
using QuestPDF.Fluent;
using QuestPDF.Helpers;
using QuestPDF.Infrastructure;
// Set license type at startup
QuestPDF.Settings.License = LicenseType.Community;
// Create and generate a PDF document
Document.Create(container =>
{
container.Page(page =>
{
// Configure page settings
page.Size(PageSizes.A4);
page.Margin(2, Unit.Centimetre);
page.PageColor(Colors.White);
page.DefaultTextStyle(x => x.FontSize(12));
// Add a header
page.Header()
.Text("Our First QuestPDF Document")
.SemiBold()
.FontSize(34)
.FontColor(Colors.Pink.Medium);
// Add content
page.Content()
.PaddingVertical(1, Unit.Centimetre)
.Column(column =>
{
column.Item().Text("Grab a coffee ☕ and let's make some PDFs!")
.FontSize(20)
.SemiBold();
});
});
})
.GeneratePdf("first-doc.pdf");
Mission accomplished – take a look at the result:

Working with Text in PDFs Using QuestPDF
QuestPDF provides a variety of text formatting options for creating well-styled documents.
Text Formatting Code Example
using QuestPDF.Fluent;
using QuestPDF.Helpers;
using QuestPDF.Infrastructure;
// Set license type at startup
QuestPDF.Settings.License = LicenseType.Community;
Document.Create(container =>
{
container.Page(page =>
{
page.Size(PageSizes.A4);
page.Margin(2, Unit.Centimetre);
page.PageColor(Colors.White);
page.DefaultTextStyle(x => x.FontSize(14));
page.Header()
.Text("Text Formatting Options in QuestPDF")
.SemiBold()
.FontSize(24);
page.Content()
.PaddingVertical(1, Unit.Centimetre)
.Column(column =>
{
column.Spacing(25);
column.Item()
.Text("Standard text with purple color")
.FontColor(Colors.Purple.Medium);
column.Item()
.Text("Bold text with orange color")
.Bold()
.FontColor(Colors.Orange.Medium);
column.Item()
.Text("Italic text with right alignment")
.Italic()
.AlignRight();
column.Item()
.Text("Underlined text with letter spacing")
.Underline()
.LetterSpacing((float)0.5);
column.Item()
.Text("Strikethrough text with large font")
.Strikethrough()
.FontSize(18);
column.Item()
.Text("Centered, bold and italic text")
.Bold()
.Italic()
.AlignCenter();
column.Item()
.Text(text =>
{
text.Span("Mixed ").FontSize(12);
text.Span("formatting ").Bold().FontColor(Colors.Blue.Medium);
text.Span("in ").Italic();
text.Span("one ").Underline();
text.Span("line").FontSize(18).FontColor(Colors.Red.Medium);
});
column.Item()
.Text(
"Justified text with longer content. This text demonstrates how QuestPDF handles justified alignment with multiple lines of content in a single text block.")
.Justify();
});
});
})
.GeneratePdf("text-formatting.pdf");
This example demonstrates a variety of text formatting options available in QuestPDF:
| Option | Description | Example |
|---|---|---|
| Font Colors | Sets the color of text. | .FontColor() |
| Font Weights | Controls the thickness of the text. | .Bold() .SemiBold() |
| Font Styles | Creates slanted text (italic). | .Italic() |
| Text Decorations | Adds lines to text, such as underlining or strikethrough. | .Underline() .Strikethrough() |
| Text Alignment | Controls the positioning of the text. | .AlignLeft() .AlignRight() .AlignCenter().Justify() |
| Font Sizing | Changes the size of the text in points. | .FontSize() |
| Letter Spacing | Adjusts the space between characters. | .LetterSpacing() |
| Mixed Formatting | Combines multiple styles in one line using Span(). | .Text(text => { text.Span()... }) |
Here is the output:

Working with Images in PDFs Using QuestPDF
QuestPDF makes it easy to embed images in your documents with flexible positioning and sizing options.
Image Code Example
using QuestPDF.Fluent;
using QuestPDF.Helpers;
using QuestPDF.Infrastructure;
// Set license type at startup
QuestPDF.Settings.License = LicenseType.Community;
Document.Create(container =>
{
container.Page(page =>
{
page.Size(PageSizes.A4);
page.Margin(1, Unit.Centimetre);
page.PageColor(Colors.White);
page.DefaultTextStyle(x => x.FontSize(12));
page.Content()
.PaddingVertical(1, Unit.Centimetre)
.Column(column =>
{
// Standard image - will scale to fit width
column.Item()
.Padding(10)
.Column(imageSection =>
{
imageSection.Item().Text("Default Image (FitWidth)").Bold();
imageSection.Item().PaddingBottom(10);
imageSection.Item().Image("image.jpg");
});
column.Spacing(10);
// Image with specific width
column.Item()
.Padding(10)
.Column(imageSection =>
{
imageSection.Item().Text("Image with Specific Width").Bold();
imageSection.Item().PaddingBottom(10);
imageSection.Item().Width(150).Image("image.jpg");
});
column.Spacing(10);
// Row of images
column.Item()
.Padding(10)
.Column(imageSection =>
{
imageSection.Item().Text("Multiple Images in a Row").Bold();
imageSection.Item().PaddingBottom(10);
imageSection.Item().Row(row =>
{
row.Spacing(10);
row.RelativeItem().Image("image.jpg");
row.RelativeItem().Image("image.jpg");
row.RelativeItem().Image("image.jpg");
});
});
});
});
})
.GeneratePdf("image-examples.pdf");
PDF preview:

QuestPDF supports the most common image formats including JPEG, PNG, BMP, and WEBP. The library handles image scaling and positioning automatically.
In QuestPDF, specify only Width() or Height() for images, not both. The library preserves aspect ratio by default and handles the pixel-to-point conversion automatically.
container
.Width(1, Unit.Inch)
.Image("image.jpg")
Working with Tables in PDFs Using QuestPDF
Tables in QuestPDF offer great flexibility for displaying structured data.
Table Code Example
using QuestPDF.Fluent;
using QuestPDF.Helpers;
using QuestPDF.Infrastructure;
// Set license type at startup
QuestPDF.Settings.License = LicenseType.Community;
Document.Create(container =>
{
container.Page(page =>
{
page.Size(PageSizes.A4);
page.Margin(1, Unit.Centimetre);
page.PageColor(Colors.White);
page.DefaultTextStyle(x => x.FontSize(12));
page.Header()
.Text("Simple Table")
.SemiBold()
.FontSize(20);
page.Content()
.PaddingVertical(1, Unit.Centimetre)
.Table(table =>
{
table.ColumnsDefinition(columns =>
{
columns.ConstantColumn(180); // Fixed width column
columns.RelativeColumn(3); // Takes 3 parts of remaining width
columns.RelativeColumn(1); // Takes 1 part of remaining width
});
// Header row spanning all columns
table.Cell().ColumnSpan(3)
.Background(Colors.Grey.Lighten2).Element(CellStyle)
.Text("Custom Column Widths")
.FontSize(14)
.Bold();
// Column description row
table.Cell().Element(CellStyle).Text("Fixed Width");
table.Cell().Element(CellStyle).Text("Relative Width (75%)");
table.Cell().Element(CellStyle).Text("Relative Width (25%)");
// Example width values
table.Cell().Element(CellStyle).Text("Banana 🍌");
table.Cell().Element(CellStyle).Text("Coffee ☕");
table.Cell().Element(CellStyle).Text("Deadline 😱");
// Helper method for consistent cell styling
static IContainer CellStyle(IContainer container)
=> container.Border(1).BorderColor(Colors.Grey.Medium).Padding(10);
});
});
})
.GeneratePdf("table-example.pdf");
Preview of the Generated PDF:

Working with Headers and Footers in PDFs Using QuestPDF
QuestPDF makes it easy to create consistent headers and footers across multiple pages.
Headers and Footers Code Example
using QuestPDF.Fluent;
using QuestPDF.Helpers;
using QuestPDF.Infrastructure;
// Set license type at startup
QuestPDF.Settings.License = LicenseType.Community;
Document.Create(container =>
{
container.Page(page =>
{
page.Size(PageSizes.A4);
page.Margin(1, Unit.Centimetre);
page.PageColor(Colors.White);
page.DefaultTextStyle(x => x.FontSize(11));
// Add a header
page.Header().Element(ComposeHeader);
// Add content
page.Content().Element(ComposeContent);
// Add a footer
page.Footer().Element(ComposeFooter);
});
})
.GeneratePdf("header-footer-example.pdf");
// Simple header composition
void ComposeHeader(IContainer container)
{
container.Border(1).BorderColor(Colors.Grey.Medium).Padding(10)
.Row(row =>
{
row.RelativeItem().Column(column =>
{
column.Item().Text("Document Title")
.FontSize(16)
.Bold();
column.Item().Text($"Generated: {DateTime.Now:d}")
.FontSize(10)
.FontColor(Colors.Grey.Medium);
});
});
}
// Main content composition
void ComposeContent(IContainer container)
{
container.PaddingVertical(10).Column(column =>
{
// Add some content for demonstration
column.Item().Text("First Page Content").FontSize(14).Bold();
column.Item().PaddingTop(5).Text(Placeholders.LoremIpsum());
column.Item().PaddingTop(10).Text(Placeholders.LoremIpsum());
// Add a line break to demonstrate multi-page content
column.Item().PageBreak();
// Continue content on next page
column.Item().Text("Second Page Content").FontSize(14).Bold();
column.Item().PaddingTop(5).Text(Placeholders.LoremIpsum());
column.Item().PaddingTop(10).Text(Placeholders.LoremIpsum());
});
}
// Simple footer composition
void ComposeFooter(IContainer container)
{
container.Border(1).BorderColor(Colors.Grey.Medium)
.PaddingVertical(5).PaddingHorizontal(10)
.Row(row =>
{
row.RelativeItem().AlignLeft().Text("Company Name")
.FontSize(10);
row.RelativeItem().AlignRight().Text(text =>
{
text.Span("Page ");
text.CurrentPageNumber();
text.Span(" of ");
text.TotalPages();
});
});
}
The header and footer appear on every page automatically. QuestPDF repeats them across all pages without any extra configuration.
Output Preview


Adding Barcodes and QR Codes to PDFs with QuestPDF
QuestPDF supports generating various types of barcodes through integration with the ZXing.Net library. This allows you to embed both linear barcodes and QR codes directly in your PDF documents.
Before using any of these examples, you must install the ZXing.Net package:
dotnet add package ZXing.Net
Here's a simple example showing how to create both linear barcodes and QR codes in your documents.
Barcode and QR Code Example
using QuestPDF.Fluent;
using QuestPDF.Helpers;
using QuestPDF.Infrastructure;
using ZXing;
using ZXing.OneD;
using ZXing.QrCode;
using ZXing.Rendering;
// Set license type at startup
QuestPDF.Settings.License = LicenseType.Community;
Document.Create(container =>
{
container.Page(page =>
{
page.Size(PageSizes.A4);
page.Margin(1, Unit.Centimetre);
page.DefaultTextStyle(x => x.FontSize(14));
page.Content()
.PaddingVertical(1, Unit.Centimetre)
.Column(column =>
{
// 1. Linear Barcode Example (Code 128)
column.Item()
.Background(Colors.Grey.Lighten4)
.Padding(15)
.Column(barcodeSection =>
{
barcodeSection.Item().Text("Code 128 Barcode").Bold();
barcodeSection.Item().PaddingBottom(10);
// Product code to encode
var productCode = "PRD12345";
barcodeSection.Item()
.Height(80)
.AlignCenter()
.Background(Colors.White)
.Padding(10)
.Svg(size =>
{
var writer = new Code128Writer();
var matrix = writer.encode(productCode, BarcodeFormat.CODE_128,
(int)size.Width, (int)size.Height);
var renderer = new SvgRenderer();
return renderer.Render(matrix, BarcodeFormat.CODE_128, productCode).Content;
});
barcodeSection.Item().PaddingBottom(10);
barcodeSection.Item()
.AlignCenter()
.Text(productCode);
});
column.Spacing(20);
// 2. QR Code Example
column.Item()
.Background(Colors.Grey.Lighten4)
.Padding(15)
.Column(qrSection =>
{
qrSection.Item().Text("QR Code").Bold();
qrSection.Item().Height(10);
// URL to encode
var url = "https://pdfbolt.com";
qrSection.Item()
.Height(150)
.AlignCenter()
.Background(Colors.White)
.Padding(10)
.Svg(size =>
{
var writer = new QRCodeWriter();
var matrix = writer.encode(url, BarcodeFormat.QR_CODE,
(int)size.Width, (int)size.Height);
var renderer = new SvgRenderer();
return renderer.Render(matrix, BarcodeFormat.QR_CODE, null).Content;
});
qrSection.Item().PaddingBottom(10);
qrSection.Item()
.AlignCenter()
.Text(url)
.FontColor(Colors.Blue.Medium);
});
});
});
})
.GeneratePdf("barcode-qrcode-examples.pdf");
These examples demonstrate:
- Linear Barcode (Code 128): Suitable for product IDs, tracking numbers, and other alphanumeric data.
- QR Code: Ideal for encoding URLs, contact information, or larger amounts of text.
Both examples use SVG rendering for high-quality output at any resolution, so your barcodes stay sharp and scannable in the final PDF.
- You can adjust the height and padding of the barcodes to fit your needs.
- QR codes can encode much more data than shown in this example (URLs, contact info, etc.).
See the Result:

Step-by-Step: Creating an Invoice PDF with QR Code in C#
Let's create a complete invoice example with QuestPDF, including a company logo, structured layout, and a QR code for payment information.
Step 1: Project Setup
First, Let's Create the Project Structure
InvoiceGenerator/
