How to Migrate from QuestPDF to IronPDF in C#
Migrating from QuestPDF to IronPDF transforms your PDF generation workflow from a proprietary C# fluent API to a standard HTML/CSS-based approach with comprehensive PDF manipulation capabilities. This guide provides a complete, step-by-step migration path that enables you to leverage existing web skills, reuse HTML templates, and gain features that QuestPDF simply cannot provide.
Why Migrate from QuestPDF to IronPDF
Understanding QuestPDF
QuestPDF is a modern, fluent API created specifically for generating PDFs programmatically in C#. Unlike some of its peers that offer comprehensive HTML-to-PDF conversion capability, QuestPDF is limited to programmatic layout API functionalities. QuestPDF excels in scenarios where developers need to generate documents from scratch using C# code, without relying on HTML.
The library is free for businesses with revenue under $1M, but it comes with a requirement to prove this revenue level, which could be a compliance burden for some. Users who surpass this threshold need to purchase a license, which must be factored into long-term planning when evaluating QuestPDF as a potential solution.
The Core Problem: No HTML Support
QuestPDF is often recommended for HTML-to-PDF conversion, but it doesn't support HTML at all. Despite being heavily promoted on developer forums, QuestPDF uses its own proprietary layout language that requires learning an entirely new DSL instead of leveraging existing web skills.
| Feature | QuestPDF | IronPDF |
|---|---|---|
| HTML-to-PDF | NOT SUPPORTED | Full support |
| CSS Styling | NOT SUPPORTED | Full CSS3 |
| Existing Templates | Must rebuild from scratch | Reuse HTML/CSS assets |
| Design Tool Compatibility | None | Any web design tool |
| Learning Curve | New proprietary DSL | Web skills transfer |
| Layout Preview | Requires IDE plugin | Preview in any browser |
| PDF Manipulation | None | Merging, splitting, editing |
IronPDF provides native HTML-to-PDF rendering that QuestPDF completely lacks, eliminating the need to manually reconstruct documents in C# code. It includes comprehensive PDF manipulation features (merge, split, edit, secure) that QuestPDF cannot perform.
The QuestPDF Licensing Model
QuestPDF's "Community License" is only free if your company has less than $1 million in annual gross revenue. Your clients (not just you as a developer) may need to purchase licenses if they exceed revenue thresholds. Unlike a simple per-developer commercial license, QuestPDF's model requires revenue disclosure and compliance tracking.
IronPDF offers simple licensing: one license per developer, no revenue audits, no client licensing requirements, and clear, predictable costs.
For teams planning .NET 10 and C# 14 adoption through 2025 and 2026, IronPDF provides transparent licensing without revenue-based audits and a standard HTML/CSS approach that leverages existing web development skills.
Before You Start
Prerequisites
- .NET Environment: .NET Framework 4.6.2+ or .NET Core 3.1+ / .NET 5/6/7/8/9+
- NuGet Access: Ability to install NuGet packages
- IronPDF License: Obtain your license key from ironpdf.com
NuGet Package Changes
# Remove QuestPDF
dotnet remove package QuestPDF
# Add IronPDF
dotnet add package IronPdf# Remove QuestPDF
dotnet remove package QuestPDF
# Add IronPDF
dotnet add package IronPdfLicense Configuration
// Add at application startup
IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY";// Add at application startup
IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY";Find QuestPDF Usage
# Find all QuestPDF usages in your codebase
grep -r "QuestPDF\|Document.Create\|\.GeneratePdf" --include="*.cs" .# Find all QuestPDF usages in your codebase
grep -r "QuestPDF\|Document.Create\|\.GeneratePdf" --include="*.cs" .Complete API Reference
Namespace Changes
// Before: QuestPDF
using QuestPDF.Fluent;
using QuestPDF.Helpers;
using QuestPDF.Infrastructure;
// After: IronPDF
using IronPdf;// Before: QuestPDF
using QuestPDF.Fluent;
using QuestPDF.Helpers;
using QuestPDF.Infrastructure;
// After: IronPDF
using IronPdf;Core API Mappings
| QuestPDF Concept | IronPDF Equivalent | Notes |
|---|---|---|
Document.Create() | new ChromePdfRenderer() | Renderer creation |
.Page() | RenderHtmlAsPdf() | Renders HTML to PDF |
.Text() | HTML <p>, <h1>, <span> | Standard HTML tags |
.Bold() | CSS font-weight: bold | Standard CSS |
.FontSize(24) | CSS font-size: 24px | Standard CSS |
.Image() | HTML <img src="..."> | Standard HTML |
.Table() | HTML <table> | Standard HTML |
.Column() | CSS display: flex; flex-direction: column | CSS Flexbox |
.Row() | CSS display: flex; flex-direction: row | CSS Flexbox |
PageSizes.A4 | RenderingOptions.PaperSize | Paper dimensions |
.Margin() | RenderingOptions.Margin* | Page margins |
.GeneratePdf() | pdf.SaveAs() | File output |
| N/A | PdfDocument.Merge() | Merge PDFs |
| N/A | PdfDocument.FromFile() | Load existing PDFs |
| N/A | pdf.SecuritySettings | PDF encryption |
Code Migration Examples
Example 1: Basic Document Creation (HTML-to-PDF)
Before (QuestPDF):
// NuGet: Install-Package QuestPDF
using QuestPDF.Fluent;
using QuestPDF.Helpers;
using QuestPDF.Infrastructure;
class Program
{
static void Main()
{
QuestPDF.Settings.License = LicenseType.Community;
Document.Create(container =>
{
container.Page(page =>
{
page.Size(PageSizes.A4);
page.Margin(2, Unit.Centimetre);
page.Content().Column(column =>
{
column.Item().Text("Hello World").FontSize(20).Bold();
column.Item().Text("This is a paragraph of text.");
});
});
}).GeneratePdf("output.pdf");
}
}// NuGet: Install-Package QuestPDF
using QuestPDF.Fluent;
using QuestPDF.Helpers;
using QuestPDF.Infrastructure;
class Program
{
static void Main()
{
QuestPDF.Settings.License = LicenseType.Community;
Document.Create(container =>
{
container.Page(page =>
{
page.Size(PageSizes.A4);
page.Margin(2, Unit.Centimetre);
page.Content().Column(column =>
{
column.Item().Text("Hello World").FontSize(20).Bold();
column.Item().Text("This is a paragraph of text.");
});
});
}).GeneratePdf("output.pdf");
}
}After (IronPDF):
// NuGet: Install-Package IronPdf
using IronPdf;
class Program
{
static void Main()
{
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf("<h1>Hello World</h1><p>This is a paragraph of text.</p>");
pdf.SaveAs("output.pdf");
}
}// NuGet: Install-Package IronPdf
using IronPdf;
class Program
{
static void Main()
{
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf("<h1>Hello World</h1><p>This is a paragraph of text.</p>");
pdf.SaveAs("output.pdf");
}
}This example demonstrates the fundamental paradigm difference. QuestPDF requires learning its fluent API: Document.Create(), container.Page(), page.Content().Column(), column.Item().Text(), with styling via method chaining like .FontSize(20).Bold(). You must also set the license type with QuestPDF.Settings.License = LicenseType.Community.
IronPDF uses standard HTML that any web developer knows: <h1> for headings, <p> for paragraphs. No proprietary DSL to learn. IronPDF's approach offers cleaner syntax and better integration with modern .NET applications. See the HTML to PDF documentation for comprehensive examples.
Example 2: Invoice Generation
Before (QuestPDF):
// NuGet: Install-Package QuestPDF
using QuestPDF.Fluent;
using QuestPDF.Helpers;
using QuestPDF.Infrastructure;
class Program
{
static void Main()
{
QuestPDF.Settings.License = LicenseType.Community;
Document.Create(container =>
{
container.Page(page =>
{
page.Size(PageSizes.A4);
page.Margin(2, Unit.Centimetre);
page.Content().Column(column =>
{
column.Item().Text("INVOICE").FontSize(24).Bold();
column.Item().Text("Invoice #: 12345").FontSize(12);
column.Item().PaddingTop(20);
column.Item().Text("Customer: John Doe");
column.Item().Text("Total: $100.00").Bold();
});
});
}).GeneratePdf("invoice.pdf");
}
}// NuGet: Install-Package QuestPDF
using QuestPDF.Fluent;
using QuestPDF.Helpers;
using QuestPDF.Infrastructure;
class Program
{
static void Main()
{
QuestPDF.Settings.License = LicenseType.Community;
Document.Create(container =>
{
container.Page(page =>
{
page.Size(PageSizes.A4);
page.Margin(2, Unit.Centimetre);
page.Content().Column(column =>
{
column.Item().Text("INVOICE").FontSize(24).Bold();
column.Item().Text("Invoice #: 12345").FontSize(12);
column.Item().PaddingTop(20);
column.Item().Text("Customer: John Doe");
column.Item().Text("Total: $100.00").Bold();
});
});
}).GeneratePdf("invoice.pdf");
}
}After (IronPDF):
// NuGet: Install-Package IronPdf
using IronPdf;
class Program
{
static void Main()
{
var htmlContent = @"
<h1>INVOICE</h1>
<p>Invoice #: 12345</p>
<br/>
<p>Customer: John Doe</p>
<p><strong>Total: $100.00</strong></p>
";
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf(htmlContent);
pdf.SaveAs("invoice.pdf");
}
}// NuGet: Install-Package IronPdf
using IronPdf;
class Program
{
static void Main()
{
var htmlContent = @"
<h1>INVOICE</h1>
<p>Invoice #: 12345</p>
<br/>
<p>Customer: John Doe</p>
<p><strong>Total: $100.00</strong></p>
";
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf(htmlContent);
pdf.SaveAs("invoice.pdf");
}
}QuestPDF uses .Column() and .Item() for layout, with .PaddingTop(20) for spacing. IronPDF uses standard HTML: <h1> for the title, <p> for paragraphs, <br/> for spacing, and <strong> for bold text.
The real advantage: with IronPDF, designers can create and modify HTML templates independently. With QuestPDF, every design change requires a C# developer to modify code. Learn more in our tutorials.
Example 3: Headers and Footers with Page Numbers
Before (QuestPDF):
// NuGet: Install-Package QuestPDF
using QuestPDF.Fluent;
using QuestPDF.Helpers;
using QuestPDF.Infrastructure;
class Program
{
static void Main()
{
QuestPDF.Settings.License = LicenseType.Community;
Document.Create(container =>
{
container.Page(page =>
{
page.Size(PageSizes.A4);
page.Margin(2, Unit.Centimetre);
page.Header().Text("Document Header").FontSize(14).Bold();
page.Content().Text("Main content of the document.");
page.Footer().AlignCenter().Text(text =>
{
text.Span("Page ");
text.CurrentPageNumber();
});
});
}).GeneratePdf("document.pdf");
}
}// NuGet: Install-Package QuestPDF
using QuestPDF.Fluent;
using QuestPDF.Helpers;
using QuestPDF.Infrastructure;
class Program
{
static void Main()
{
QuestPDF.Settings.License = LicenseType.Community;
Document.Create(container =>
{
container.Page(page =>
{
page.Size(PageSizes.A4);
page.Margin(2, Unit.Centimetre);
page.Header().Text("Document Header").FontSize(14).Bold();
page.Content().Text("Main content of the document.");
page.Footer().AlignCenter().Text(text =>
{
text.Span("Page ");
text.CurrentPageNumber();
});
});
}).GeneratePdf("document.pdf");
}
}After (IronPDF):
// NuGet: Install-Package IronPdf
using IronPdf;
class Program
{
static void Main()
{
var htmlContent = "<p>Main content of the document.</p>";
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf(htmlContent);
pdf.Header = new TextHeaderFooter()
{
CenterText = "Document Header",
FontSize = 14
};
pdf.Footer = new TextHeaderFooter()
{
CenterText = "Page {page}"
};
pdf.SaveAs("document.pdf");
}
}// NuGet: Install-Package IronPdf
using IronPdf;
class Program
{
static void Main()
{
var htmlContent = "<p>Main content of the document.</p>";
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf(htmlContent);
pdf.Header = new TextHeaderFooter()
{
CenterText = "Document Header",
FontSize = 14
};
pdf.Footer = new TextHeaderFooter()
{
CenterText = "Page {page}"
};
pdf.SaveAs("document.pdf");
}
}QuestPDF uses page.Header() and page.Footer() with fluent methods like .AlignCenter() and .CurrentPageNumber(). IronPDF uses TextHeaderFooter objects with properties like CenterText and FontSize. The {page} placeholder automatically inserts the current page number.
Critical Migration Notes
The Paradigm Shift
The fundamental change is moving from a proprietary C# DSL to standard HTML/CSS:
// QuestPDF: Proprietary fluent API
container.Page(page =>
{
page.Content().Column(column =>
{
column.Item().Text("Invoice").Bold().FontSize(24);
column.Item().Row(row =>
{
row.RelativeItem().Text("Customer:");
row.RelativeItem().Text("Acme Corp");
});
});
});
// IronPDF: Standard HTML/CSS
var html = @"
<div style='font-family: Arial; padding: 40px;'>
<h1 style='font-weight: bold; font-size: 24px;'>Invoice</h1>
<div style='display: flex; justify-content: space-between;'>
<span>Customer:</span>
<span>Acme Corp</span>
</div>
</div>";
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf(html);// QuestPDF: Proprietary fluent API
container.Page(page =>
{
page.Content().Column(column =>
{
column.Item().Text("Invoice").Bold().FontSize(24);
column.Item().Row(row =>
{
row.RelativeItem().Text("Customer:");
row.RelativeItem().Text("Acme Corp");
});
});
});
// IronPDF: Standard HTML/CSS
var html = @"
<div style='font-family: Arial; padding: 40px;'>
<h1 style='font-weight: bold; font-size: 24px;'>Invoice</h1>
<div style='display: flex; justify-content: space-between;'>
<span>Customer:</span>
<span>Acme Corp</span>
</div>
</div>";
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf(html);Layout Pattern Conversions
| QuestPDF Pattern | HTML/CSS Equivalent |
|---|---|
.Column() | display: flex; flex-direction: column |
.Row() | display: flex; flex-direction: row |
.RelativeItem() | flex: 1 |
.Table() | <table> element |
.PaddingTop(20) | padding-top: 20px or <br/> |
.AlignCenter() | text-align: center |
.FontSize(24) | font-size: 24px |
.Bold() | font-weight: bold or <strong> |
Page Settings Conversion
// QuestPDF
page.Size(PageSizes.A4);
page.Margin(2, Unit.Centimetre);
// IronPDF
var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.PaperSize = PdfPaperSize.A4;
renderer.RenderingOptions.MarginTop = 20; // mm (2cm = 20mm)
renderer.RenderingOptions.MarginBottom = 20;
renderer.RenderingOptions.MarginLeft = 20;
renderer.RenderingOptions.MarginRight = 20;// QuestPDF
page.Size(PageSizes.A4);
page.Margin(2, Unit.Centimetre);
// IronPDF
var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.PaperSize = PdfPaperSize.A4;
renderer.RenderingOptions.MarginTop = 20; // mm (2cm = 20mm)
renderer.RenderingOptions.MarginBottom = 20;
renderer.RenderingOptions.MarginLeft = 20;
renderer.RenderingOptions.MarginRight = 20;New Capabilities After Migration
After migrating to IronPDF, you gain capabilities that QuestPDF cannot provide:
PDF Merging
var cover = renderer.RenderHtmlAsPdf("<h1>Cover</h1>");
var content = renderer.RenderHtmlAsPdf(reportHtml);
var existing = PdfDocument.FromFile("appendix.pdf");
var merged = PdfDocument.Merge(cover, content, existing);
merged.SaveAs("complete.pdf");var cover = renderer.RenderHtmlAsPdf("<h1>Cover</h1>");
var content = renderer.RenderHtmlAsPdf(reportHtml);
var existing = PdfDocument.FromFile("appendix.pdf");
var merged = PdfDocument.Merge(cover, content, existing);
merged.SaveAs("complete.pdf");PDF Security
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SecuritySettings.OwnerPassword = "admin";
pdf.SecuritySettings.UserPassword = "reader";
pdf.SecuritySettings.AllowUserPrinting = PdfPrintSecurity.FullPrintRights;
pdf.SaveAs("protected.pdf");var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SecuritySettings.OwnerPassword = "admin";
pdf.SecuritySettings.UserPassword = "reader";
pdf.SecuritySettings.AllowUserPrinting = PdfPrintSecurity.FullPrintRights;
pdf.SaveAs("protected.pdf");URL to PDF
var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.EnableJavaScript = true;
var pdf = renderer.RenderUrlAsPdf("https://example.com/report");
pdf.SaveAs("webpage.pdf");var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.EnableJavaScript = true;
var pdf = renderer.RenderUrlAsPdf("https://example.com/report");
pdf.SaveAs("webpage.pdf");Load and Edit Existing PDFs
var pdf = PdfDocument.FromFile("existing.pdf");
// Modify, merge, add security, etc.
pdf.SaveAs("modified.pdf");var pdf = PdfDocument.FromFile("existing.pdf");
// Modify, merge, add security, etc.
pdf.SaveAs("modified.pdf");Feature Comparison Summary
| Feature | QuestPDF | IronPDF |
|---|---|---|
| HTML-to-PDF | Not supported | Primary feature |
| Learning Curve | Proprietary DSL | Standard web skills |
| Template Preview | Plugin required | Any browser |
| Design Collaboration | Developers only | Designers + Developers |
| Existing Assets | Must rebuild | Reuse HTML/CSS |
| PDF Manipulation | Not supported | Full support |
| Security/Signing | Not supported | Full support |
| Licensing Model | Revenue-based | Per-developer |
| Client Impact | May need licenses | None |
| Bootstrap/Tailwind | Not supported | Full support |
| URL to PDF | Not supported | Full support |
Migration Checklist
Pre-Migration
- Identify all QuestPDF document templates (
Document.Create,.GeneratePdf) - Document the DSL patterns used (
.Column(),.Row(),.Table(),.Text()) - Map styling methods to CSS equivalents
- Obtain IronPDF license key from ironpdf.com
Package Changes
- Remove
QuestPDFNuGet package - Install
IronPdfNuGet package:dotnet add package IronPdf
Code Changes
- Update namespace imports
- Remove
QuestPDF.Settings.License = LicenseType.Community - Convert
Document.Create()pattern toChromePdfRenderer+ HTML - Replace
.Column()/.Row()with CSS Flexbox - Replace
.Table()with HTML<table>elements - Convert
.Text().Bold().FontSize(24)to<h1 style='...'> - Replace
page.Header()/page.Footer()withTextHeaderFooter - Replace
.CurrentPageNumber()with{page}placeholder - Convert
.GeneratePdf()topdf.SaveAs() - Add license initialization at application startup
Post-Migration
- Visual comparison of PDF output
- Test multi-page documents for correct page breaks
- Add new capabilities (security, merging, URL-to-PDF) as needed






