Gotenberg vs IronPDF: Technical Comparison Guide
When .NET developers assess PDF generation solutions, Gotenberg stands out as a Docker-based microservice that converts HTML to PDF through REST API calls. While adaptable for diverse architectures, Gotenberg introduces notable infrastructure overhead—Docker containers, network latency, and operational complexity. IronPDF offers an alternative: an in-process NuGet package providing the same Chromium-based rendering without containers, network calls, or infrastructure management.
This comparison looks at both solutions across technically relevant dimensions to assist professional developers and architects in making informed decisions for their .NET PDF needs.
Understanding Gotenberg
Gotenberg is a Docker-based microservice architecture for PDF generation. It runs as a separate container that exposes REST API endpoints for converting HTML, URLs, and other formats to PDF. Every PDF operation requires an HTTP call to the Gotenberg service.
Gotenberg uses endpoints like POST /forms/chromium/convert/html for HTML-to-PDF and POST /forms/chromium/convert/url for URL-to-PDF conversion. Configuration is passed via multipart/form-data with string-based parameters like paperWidth, paperHeight, marginTop, and marginBottom (in inches). The service requires Docker deployment, container orchestration (Kubernetes/Docker Compose), and network infrastructure.
The architecture requires:
- Docker container deployment and management
- Network communication for every PDF request (10-100ms+ latency)
- Container cold start handling (2-5 seconds for first requests)
- Health check endpoints and service monitoring
- Multipart/form-data construction for every request
Understanding IronPDF
IronPDF is a native .NET library that runs in-process as a NuGet package. It provides Chromium-based HTML rendering without external services, network calls, or container infrastructure.
IronPDF uses ChromePdfRenderer as its primary rendering class with methods like RenderHtmlAsPdf() and RenderUrlAsPdf(). Configuration uses typed C# properties on RenderingOptions including PaperSize, MarginTop, MarginBottom (in millimeters). Documents are saved with SaveAs() or accessed as BinaryData.
The library requires only:
- NuGet package installation (
dotnet add package IronPdf) - License key configuration
- Standard .NET project setup
Architecture and Infrastructure Comparison
The fundamental difference between these solutions lies in their deployment and runtime architecture.
| Factor | Gotenberg | IronPDF |
|---|---|---|
| Deployment | Docker container + orchestration | Single NuGet package |
| Architecture | Microservice (REST API) | In-process library |
| Latency per request | 10-100ms+ (network round-trip) | < 1ms overhead |
| Cold start | 2-5 seconds (container init) | 1-2 seconds (first render only) |
| Infrastructure | Docker, Kubernetes, load balancers | None required |
| Network dependency | Required | None |
| Failure modes | Network, container, service failures | Standard .NET exceptions |
| API style | REST multipart/form-data | Native C# method calls |
| Scaling | Horizontal (more containers) | Vertical (in-process) |
| Debugging | Distributed tracing | Standard debugger |
| Memory management | Separate container (512MB-2GB) | Shared application memory |
| Version control | Container image tags | NuGet package versions |
| Health checks | HTTP endpoints required | Not needed (in-process) |
| CI/CD complexity | Container builds, registry pushes | Standard .NET build |
Gotenberg's Docker-based approach requires container deployment, health monitoring, and network infrastructure management. IronPDF eliminates this infrastructure layer entirely by running in-process.
Code Comparison: Common PDF Operations
Basic HTML to PDF Conversion
The most fundamental operation demonstrates the architectural difference clearly.
Gotenberg:
using System;
using System.Net.Http;
using System.Threading.Tasks;
using System.IO;
class GotenbergExample
{
static async Task Main()
{
var gotenbergUrl = "http://localhost:3000/forms/chromium/convert/html";
using var client = new HttpClient();
using var content = new MultipartFormDataContent();
var html = "<html><body><h1>Hello from Gotenberg</h1></body></html>";
content.Add(new StringContent(html), "files", "index.html");
var response = await client.PostAsync(gotenbergUrl, content);
var pdfBytes = await response.Content.ReadAsByteArrayAsync();
await File.WriteAllBytesAsync("output.pdf", pdfBytes);
Console.WriteLine("PDF generated successfully");
}
}using System;
using System.Net.Http;
using System.Threading.Tasks;
using System.IO;
class GotenbergExample
{
static async Task Main()
{
var gotenbergUrl = "http://localhost:3000/forms/chromium/convert/html";
using var client = new HttpClient();
using var content = new MultipartFormDataContent();
var html = "<html><body><h1>Hello from Gotenberg</h1></body></html>";
content.Add(new StringContent(html), "files", "index.html");
var response = await client.PostAsync(gotenbergUrl, content);
var pdfBytes = await response.Content.ReadAsByteArrayAsync();
await File.WriteAllBytesAsync("output.pdf", pdfBytes);
Console.WriteLine("PDF generated successfully");
}
}IronPDF:
// NuGet: Install-Package IronPdf
using System;
using IronPdf;
class IronPdfExample
{
static void Main()
{
var renderer = new ChromePdfRenderer();
var html = "<html><body><h1>Hello from IronPDF</h1></body></html>";
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("output.pdf");
Console.WriteLine("PDF generated successfully");
}
}// NuGet: Install-Package IronPdf
using System;
using IronPdf;
class IronPdfExample
{
static void Main()
{
var renderer = new ChromePdfRenderer();
var html = "<html><body><h1>Hello from IronPDF</h1></body></html>";
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("output.pdf");
Console.WriteLine("PDF generated successfully");
}
}Gotenberg requires creating an HttpClient, constructing MultipartFormDataContent, adding the HTML as a file attachment with a specific filename (index.html), making an async HTTP POST to the Gotenberg service endpoint, reading the response bytes, and writing to disk. Every request goes over the network with associated latency and failure modes.
IronPDF creates a ChromePdfRenderer, calls RenderHtmlAsPdf() with the HTML string, and saves with SaveAs(). The operation is synchronous, in-process, and uses typed methods rather than string-based form data.
For advanced HTML rendering options, explore the HTML to PDF conversion guide.
URL to PDF Conversion
Converting live web pages to PDF shows similar architectural patterns.
Gotenberg:
using System;
using System.Net.Http;
using System.Threading.Tasks;
using System.IO;
class GotenbergUrlToPdf
{
static async Task Main()
{
var gotenbergUrl = "http://localhost:3000/forms/chromium/convert/url";
using var client = new HttpClient();
using var content = new MultipartFormDataContent();
content.Add(new StringContent("https://example.com"), "url");
var response = await client.PostAsync(gotenbergUrl, content);
var pdfBytes = await response.Content.ReadAsByteArrayAsync();
await File.WriteAllBytesAsync("webpage.pdf", pdfBytes);
Console.WriteLine("PDF from URL generated successfully");
}
}using System;
using System.Net.Http;
using System.Threading.Tasks;
using System.IO;
class GotenbergUrlToPdf
{
static async Task Main()
{
var gotenbergUrl = "http://localhost:3000/forms/chromium/convert/url";
using var client = new HttpClient();
using var content = new MultipartFormDataContent();
content.Add(new StringContent("https://example.com"), "url");
var response = await client.PostAsync(gotenbergUrl, content);
var pdfBytes = await response.Content.ReadAsByteArrayAsync();
await File.WriteAllBytesAsync("webpage.pdf", pdfBytes);
Console.WriteLine("PDF from URL generated successfully");
}
}IronPDF:
// NuGet: Install-Package IronPdf
using System;
using IronPdf;
class IronPdfUrlToPdf
{
static void Main()
{
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderUrlAsPdf("https://example.com");
pdf.SaveAs("webpage.pdf");
Console.WriteLine("PDF from URL generated successfully");
}
}// NuGet: Install-Package IronPdf
using System;
using IronPdf;
class IronPdfUrlToPdf
{
static void Main()
{
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderUrlAsPdf("https://example.com");
pdf.SaveAs("webpage.pdf");
Console.WriteLine("PDF from URL generated successfully");
}
}Gotenberg uses the /forms/chromium/convert/url endpoint with the URL passed as form data. IronPDF calls RenderUrlAsPdf() directly with the URL string—a single method call replacing the HTTP infrastructure.
Custom Page Size and Margins
Configuration handling reveals the API design differences.
Gotenberg:
using System;
using System.Net.Http;
using System.Threading.Tasks;
using System.IO;
class GotenbergCustomSize
{
static async Task Main()
{
var gotenbergUrl = "http://localhost:3000/forms/chromium/convert/html";
using var client = new HttpClient();
using var content = new MultipartFormDataContent();
var html = "<html><body><h1>Custom Size PDF</h1></body></html>";
content.Add(new StringContent(html), "files", "index.html");
content.Add(new StringContent("8.5"), "paperWidth");
content.Add(new StringContent("11"), "paperHeight");
content.Add(new StringContent("0.5"), "marginTop");
content.Add(new StringContent("0.5"), "marginBottom");
var response = await client.PostAsync(gotenbergUrl, content);
var pdfBytes = await response.Content.ReadAsByteArrayAsync();
await File.WriteAllBytesAsync("custom-size.pdf", pdfBytes);
Console.WriteLine("Custom size PDF generated successfully");
}
}using System;
using System.Net.Http;
using System.Threading.Tasks;
using System.IO;
class GotenbergCustomSize
{
static async Task Main()
{
var gotenbergUrl = "http://localhost:3000/forms/chromium/convert/html";
using var client = new HttpClient();
using var content = new MultipartFormDataContent();
var html = "<html><body><h1>Custom Size PDF</h1></body></html>";
content.Add(new StringContent(html), "files", "index.html");
content.Add(new StringContent("8.5"), "paperWidth");
content.Add(new StringContent("11"), "paperHeight");
content.Add(new StringContent("0.5"), "marginTop");
content.Add(new StringContent("0.5"), "marginBottom");
var response = await client.PostAsync(gotenbergUrl, content);
var pdfBytes = await response.Content.ReadAsByteArrayAsync();
await File.WriteAllBytesAsync("custom-size.pdf", pdfBytes);
Console.WriteLine("Custom size PDF generated successfully");
}
}IronPDF:
// NuGet: Install-Package IronPdf
using System;
using IronPdf;
using IronPdf.Rendering;
class IronPdfCustomSize
{
static void Main()
{
var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.PaperSize = PdfPaperSize.Letter;
renderer.RenderingOptions.MarginTop = 50;
renderer.RenderingOptions.MarginBottom = 50;
var html = "<html><body><h1>Custom Size PDF</h1></body></html>";
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("custom-size.pdf");
Console.WriteLine("Custom size PDF generated successfully");
}
}// NuGet: Install-Package IronPdf
using System;
using IronPdf;
using IronPdf.Rendering;
class IronPdfCustomSize
{
static void Main()
{
var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.PaperSize = PdfPaperSize.Letter;
renderer.RenderingOptions.MarginTop = 50;
renderer.RenderingOptions.MarginBottom = 50;
var html = "<html><body><h1>Custom Size PDF</h1></body></html>";
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("custom-size.pdf");
Console.WriteLine("Custom size PDF generated successfully");
}
}Gotenberg uses string-based parameters ("8.5", "11", "0.5") added to multipart form data. Paper dimensions are in inches. Each parameter is a separate Add() call with no type checking or IntelliSense support.
IronPDF uses typed properties on RenderingOptions. PaperSize accepts an enum (PdfPaperSize.Letter), and margins are numeric values in millimeters. The typed API provides compile-time checking and IDE support.
Learn more about rendering configuration in the IronPDF tutorials.
API Mapping Reference
For developers evaluating Gotenberg migration or comparing capabilities, this mapping shows equivalent operations:
Endpoint to Method Mapping
| Gotenberg Route | IronPDF Equivalent |
|---|---|
POST /forms/chromium/convert/html | ChromePdfRenderer.RenderHtmlAsPdf() |
POST /forms/chromium/convert/url | ChromePdfRenderer.RenderUrlAsPdf() |
POST /forms/chromium/convert/markdown | Render Markdown as HTML first |
POST /forms/pdfengines/merge | PdfDocument.Merge() |
POST /forms/pdfengines/metadata/read | pdf.MetaData |
POST /forms/pdfengines/metadata/write | pdf.MetaData.Author = "..." |
GET /health | N/A |
Form Parameter to RenderingOptions Mapping
| Gotenberg Parameter | IronPDF Property | Conversion Notes |
|---|---|---|
paperWidth (inches) | RenderingOptions.SetCustomPaperSizeInInches() | Use method for custom |
paperHeight (inches) | RenderingOptions.SetCustomPaperSizeInInches() | Use method for custom |
marginTop (inches) | RenderingOptions.MarginTop | Multiply by 25.4 for mm |
marginBottom (inches) | RenderingOptions.MarginBottom | Multiply by 25.4 for mm |
marginLeft (inches) | RenderingOptions.MarginLeft | Multiply by 25.4 for mm |
marginRight (inches) | RenderingOptions.MarginRight | Multiply by 25.4 for mm |
printBackground | RenderingOptions.PrintHtmlBackgrounds | Boolean |
landscape | RenderingOptions.PaperOrientation | Landscape enum |
scale | RenderingOptions.Zoom | Percentage (100 = 1.0) |
waitDelay | RenderingOptions.RenderDelay | Convert to milliseconds |
emulatedMediaType | RenderingOptions.CssMediaType | Screen or Print |
Note the unit conversion: Gotenberg uses inches for margins (e.g., "0.5" = 0.5 inches = 12.7mm), while IronPDF uses millimeters.
Infrastructure Comparison
Gotenberg Docker Compose
Gotenberg requires container infrastructure:
# Gotenberg requires container management
version: '3.8'
services:
app:
depends_on:
- gotenberg
environment:
- GOTENBERG_URL=http://gotenberg:3000
gotenberg:
image: gotenberg/gotenberg:8
ports:
- "3000:3000"
deploy:
resources:
limits:
memory: 2G
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
interval: 30s# Gotenberg requires container management
version: '3.8'
services:
app:
depends_on:
- gotenberg
environment:
- GOTENBERG_URL=http://gotenberg:3000
gotenberg:
image: gotenberg/gotenberg:8
ports:
- "3000:3000"
deploy:
resources:
limits:
memory: 2G
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
interval: 30sIronPDF Configuration
IronPDF requires no additional services:
# IronPDF - No additional services needed
version: '3.8'
services:
app:
environment:
- IRONPDF_LICENSE_KEY=${IRONPDF_LICENSE_KEY}
# No Gotenberg service. No health checks. No resource limits.# IronPDF - No additional services needed
version: '3.8'
services:
app:
environment:
- IRONPDF_LICENSE_KEY=${IRONPDF_LICENSE_KEY}
# No Gotenberg service. No health checks. No resource limits.The infrastructure difference is substantial: Gotenberg requires container deployment, health monitoring, resource allocation, and service dependencies. IronPDF runs in-process with the application.
Performance Characteristics
| Operation | Gotenberg (Warm Container) | Gotenberg (Cold Start) | IronPDF (First Render) | IronPDF (Subsequent) |
|---|---|---|---|---|
| Simple HTML | 150-300ms | 2-5 seconds | 1-2 seconds | 50-150ms |
| Complex HTML | 500-1500ms | 3-7 seconds | 1.5-3 seconds | 200-800ms |
| URL Render | 1-5 seconds | 3-10 seconds | 1-5 seconds | 500ms-3s |
| PDF Merge | 200-500ms | 2-5 seconds | 100-300ms | 100-300ms |
Gotenberg's network round-trip adds 10-100ms+ per request. Container cold starts add 2-5 seconds. IronPDF's first render incurs Chromium initialization (1-2 seconds), but subsequent renders have minimal overhead.
When Teams Consider Moving from Gotenberg to IronPDF
Development teams evaluate transitioning from Gotenberg to IronPDF for several reasons:
Infrastructure Overhead: Gotenberg requires Docker, container orchestration (Kubernetes/Docker Compose), service discovery, and load balancing. Teams seeking simpler deployment find IronPDF's NuGet-only approach eliminates these infrastructure concerns.
Network Latency: Every Gotenberg PDF operation requires an HTTP call to a separate service—adding 10-100ms+ per request. For high-volume applications, this overhead accumulates. IronPDF's in-process approach has negligible overhead after initialization.
Cold Start Issues: Container startup can add 2-5 seconds to first requests. Even warm containers have network overhead. Every pod restart, scale-up event, or deployment triggers cold starts. IronPDF's cold start occurs once per application lifetime.
Operational Complexity: Gotenberg requires managing container health, scaling, logging, and monitoring as separate concerns. Network timeouts, service unavailability, and container crashes become application concerns. IronPDF uses standard .NET exception handling.
Multipart Form Data API: Every Gotenberg request requires constructing multipart/form-data payloads with string-based parameters—verbose and without compile-time type checking. IronPDF provides typed C# properties with IntelliSense support.
Version Management: Gotenberg images update separately from your application. API changes can break integrations. IronPDF versions are managed through NuGet with standard .NET dependency management.
Strengths and Considerations
Gotenberg Strengths
- Polyglot Architecture: Works with any language that can make HTTP calls
- Language Agnostic: Not tied to .NET ecosystem
- MIT License: Free and open source
- Microservices Pattern: Fits containerized architectures
Gotenberg Considerations
- Infrastructure Overhead: Docker, Kubernetes, load balancers required
- Network Latency: 10-100ms+ per request
- Cold Starts: 2-5 seconds container initialization
- String-Based API: No type safety or IntelliSense
- Distributed Debugging: Requires distributed tracing
- Health Monitoring: Additional endpoints to manage
IronPDF Strengths
- Zero Infrastructure: NuGet package only
- In-Process Performance: No network latency after initialization
- Type-Safe API: Strongly-typed properties with IntelliSense
- Standard Debugging: Normal .NET debugger works
- Comprehensive Resources: Extensive tutorials and documentation
- Professional Support: Commercial license includes support
IronPDF Considerations
- .NET Specific: Designed for .NET ecosystem
- Commercial License: Required for production use
Gotenberg and IronPDF represent fundamentally different approaches to PDF generation in .NET applications. Gotenberg's Docker-based microservice architecture introduces container management, network latency, and operational complexity. Every PDF operation requires HTTP communication with associated failure modes and cold start penalties.
IronPDF provides the same Chromium-based rendering as an in-process library. The NuGet package eliminates Docker containers, network calls, and infrastructure management. Typed C# APIs replace string-based multipart form data. Standard .NET exception handling replaces HTTP status codes and network failure modes.
As organizations plan for .NET 10, C# 14, and application development through 2026, the choice between microservice infrastructure overhead and in-process library simplicity significantly impacts deployment and operational complexity. Teams seeking to reduce infrastructure burden while maintaining HTML/CSS/JavaScript rendering fidelity will find IronPDF addresses these requirements effectively.
Start evaluating IronPDF with a free trial and explore the comprehensive documentation to assess fit for your specific requirements.