How to Migrate from Gotenberg to IronPDF in C#
Migrating from Gotenberg to IronPDF transforms your .NET PDF workflow from a Docker-based microservice architecture with HTTP API calls to an in-process native C# library. This guide provides a comprehensive, step-by-step migration path that eliminates infrastructure overhead, network latency, and container management complexity for professional .NET developers.
Why Migrate from Gotenberg to IronPDF
The Gotenberg Architecture Problem
Gotenberg is a Docker-based microservice architecture for PDF generation. While powerful and flexible, it introduces significant complexity for C# applications:
-
Infrastructure Overhead: Requires Docker, container orchestration (Kubernetes/Docker Compose), service discovery, and load balancing. Every deployment becomes more complex.
-
Network Latency: Every PDF operation requires an HTTP call to a separate service—adding 10-100ms+ per request. This latency compounds quickly in high-volume scenarios.
-
Cold Start Issues: Container startup can add 2-5 seconds to first requests. Every pod restart, every scale-up event, and every deployment triggers cold starts.
-
Operational Complexity: You must manage container health, scaling, logging, and monitoring as separate concerns from your main application.
-
Multipart Form Data: Every request requires constructing multipart/form-data payloads—verbose, error-prone, and tedious to maintain.
-
Failure Points: Network timeouts, service unavailability, and container crashes all become your responsibility to handle.
- Version Management: Gotenberg images update separately from your application; API changes can break integrations unexpectedly.
Gotenberg vs IronPDF Comparison
| Aspect | 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 |
| 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 needed | Standard debugger |
| Version Control | Container image tags | NuGet package versions |
For teams planning .NET 10 and C# 14 adoption through 2025 and 2026, IronPDF provides a future-proof foundation with zero infrastructure dependencies that integrates natively with modern .NET patterns.
Migration Complexity Assessment
Estimated Effort by Feature
| Feature | Migration Complexity |
|---|---|
| HTML to PDF | Very Low |
| URL to PDF | Very Low |
| Custom Paper Size | Low |
| Margins | Low |
| PDF Merging | Low |
| Headers/Footers | Medium |
| Wait Delays | Low |
| PDF/A Conversion | Low |
Paradigm Shift
The fundamental shift in this Gotenberg migration is from HTTP API calls with multipart form data to native C# method calls:
Gotenberg: HTTP POST multipart/form-data to Docker container
IronPDF: Direct method calls on C# objects
Before You Start
Prerequisites
- .NET Version: IronPDF supports .NET Framework 4.6.2+ and .NET Core 3.1+ / .NET 5/6/7/8/9+
- License Key: Obtain your IronPDF license key from ironpdf.com
- Plan Infrastructure Removal: Document Gotenberg containers for decommissioning post-migration
Identify All Gotenberg Usage
# Find direct HTTP calls to Gotenberg
grep -r "gotenberg\|/forms/chromium\|/forms/libreoffice\|/forms/pdfengines" --include="*.cs" .
# Find GotenbergSharpApiClient usage
grep -r "GotenbergSharpClient\|Gotenberg.Sharp\|ChromiumRequest" --include="*.cs" .
# Find Docker/Kubernetes Gotenberg configuration
grep -r "gotenberg/gotenberg\|gotenberg:" --include="*.yml" --include="*.yaml" .
# Find direct HTTP calls to Gotenberg
grep -r "gotenberg\|/forms/chromium\|/forms/libreoffice\|/forms/pdfengines" --include="*.cs" .
# Find GotenbergSharpApiClient usage
grep -r "GotenbergSharpClient\|Gotenberg.Sharp\|ChromiumRequest" --include="*.cs" .
# Find Docker/Kubernetes Gotenberg configuration
grep -r "gotenberg/gotenberg\|gotenberg:" --include="*.yml" --include="*.yaml" .
NuGet Package Changes
# Remove Gotenberg client (if using)
dotnet remove package Gotenberg.Sharp.API.Client
# Install IronPDF
dotnet add package IronPdf
# Remove Gotenberg client (if using)
dotnet remove package Gotenberg.Sharp.API.Client
# Install IronPDF
dotnet add package IronPdf
Quick Start Migration
Step 1: Update License Configuration
Before (Gotenberg):
Gotenberg requires no license but requires Docker infrastructure with container URLs.
private readonly string _gotenbergUrl = "http://localhost:3000";
private readonly string _gotenbergUrl = "http://localhost:3000";
Private ReadOnly _gotenbergUrl As String = "http://localhost:3000"
After (IronPDF):
// Set once at application startup
IronPdf.License.LicenseKey = "YOUR-IRONPDF-LICENSE-KEY";
// Set once at application startup
IronPdf.License.LicenseKey = "YOUR-IRONPDF-LICENSE-KEY";
' Set once at application startup
IronPdf.License.LicenseKey = "YOUR-IRONPDF-LICENSE-KEY"
Step 2: Update Namespace Imports
// Before (Gotenberg)
using System.Net.Http;
using System.Threading.Tasks;
using System.IO;
// After (IronPDF)
using IronPdf;
using IronPdf.Rendering;
// Before (Gotenberg)
using System.Net.Http;
using System.Threading.Tasks;
using System.IO;
// After (IronPDF)
using IronPdf;
using IronPdf.Rendering;
Imports System.Net.Http
Imports System.Threading.Tasks
Imports System.IO
Imports IronPdf
Imports IronPdf.Rendering
Complete API Reference
Gotenberg Endpoint to IronPDF Mapping
| Gotenberg Route | IronPDF Equivalent |
|---|---|
POST /forms/chromium/convert/html |
ChromePdfRenderer.RenderHtmlAsPdf() |
POST /forms/chromium/convert/url |
ChromePdfRenderer.RenderUrlAsPdf() |
POST /forms/pdfengines/merge |
PdfDocument.Merge() |
POST /forms/pdfengines/convert |
pdf.SaveAs() with settings |
GET /health |
N/A |
Form Parameter to RenderingOptions Mapping
| Gotenberg Parameter | IronPDF Property | Conversion Notes |
|---|---|---|
paperWidth (inches) |
RenderingOptions.PaperSize |
Use enum or custom size |
paperHeight (inches) |
RenderingOptions.PaperSize |
Use enum or custom size |
marginTop (inches) |
RenderingOptions.MarginTop |
Multiply by 25.4 for mm |
marginBottom (inches) |
RenderingOptions.MarginBottom |
Multiply by 25.4 for mm |
printBackground |
RenderingOptions.PrintHtmlBackgrounds |
Boolean |
landscape |
RenderingOptions.PaperOrientation |
Landscape enum |
waitDelay |
RenderingOptions.RenderDelay |
Convert to milliseconds |
Code Migration Examples
Example 1: Basic HTML to PDF
Before (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");
}
}
Imports System
Imports System.Net.Http
Imports System.Threading.Tasks
Imports System.IO
Module GotenbergExample
Async Function Main() As Task
Dim gotenbergUrl = "http://localhost:3000/forms/chromium/convert/html"
Using client As New HttpClient()
Using content As New MultipartFormDataContent()
Dim html = "<html><body><h1>Hello from Gotenberg</h1></body></html>"
content.Add(New StringContent(html), "files", "index.html")
Dim response = Await client.PostAsync(gotenbergUrl, content)
Dim pdfBytes = Await response.Content.ReadAsByteArrayAsync()
Await File.WriteAllBytesAsync("output.pdf", pdfBytes)
Console.WriteLine("PDF generated successfully")
End Using
End Using
End Function
End Module
After (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");
}
}
Imports System
Imports IronPdf
Class IronPdfExample
Shared Sub Main()
Dim renderer = New ChromePdfRenderer()
Dim html = "<html><body><h1>Hello from IronPDF</h1></body></html>"
Dim pdf = renderer.RenderHtmlAsPdf(html)
pdf.SaveAs("output.pdf")
Console.WriteLine("PDF generated successfully")
End Sub
End Class
The difference is substantial: Gotenberg requires constructing an HttpClient, building MultipartFormDataContent, making an async HTTP POST to a running Docker container, and handling the byte array response. IronPDF reduces this to three lines with a ChromePdfRenderer method call—no network overhead, no container dependency, no async complexity. See the HTML to PDF documentation for additional rendering options.
Example 2: URL to PDF Conversion
Before (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");
}
}
Imports System
Imports System.Net.Http
Imports System.Threading.Tasks
Imports System.IO
Module GotenbergUrlToPdf
Async Function Main() As Task
Dim gotenbergUrl As String = "http://localhost:3000/forms/chromium/convert/url"
Using client As New HttpClient()
Using content As New MultipartFormDataContent()
content.Add(New StringContent("https://example.com"), "url")
Dim response As HttpResponseMessage = Await client.PostAsync(gotenbergUrl, content)
Dim pdfBytes As Byte() = Await response.Content.ReadAsByteArrayAsync()
Await File.WriteAllBytesAsync("webpage.pdf", pdfBytes)
Console.WriteLine("PDF from URL generated successfully")
End Using
End Using
End Function
End Module
After (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");
}
}
Imports System
Imports IronPdf
Class IronPdfUrlToPdf
Shared Sub Main()
Dim renderer As New ChromePdfRenderer()
Dim pdf = renderer.RenderUrlAsPdf("https://example.com")
pdf.SaveAs("webpage.pdf")
Console.WriteLine("PDF from URL generated successfully")
End Sub
End Class
The Gotenberg approach requires a different endpoint (/forms/chromium/convert/url), building multipart content with the URL as a form field, and handling async HTTP responses. IronPDF's RenderUrlAsPdf() method accepts the URL directly and returns a PdfDocument object synchronously. Learn more about URL to PDF conversion.
Example 3: Custom Paper Size and Margins
Before (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");
}
}
Imports System
Imports System.Net.Http
Imports System.Threading.Tasks
Imports System.IO
Class GotenbergCustomSize
Shared Async Function Main() As Task
Dim gotenbergUrl = "http://localhost:3000/forms/chromium/convert/html"
Using client As New HttpClient()
Using content As New MultipartFormDataContent()
Dim 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")
Dim response = Await client.PostAsync(gotenbergUrl, content)
Dim pdfBytes = Await response.Content.ReadAsByteArrayAsync()
Await File.WriteAllBytesAsync("custom-size.pdf", pdfBytes)
Console.WriteLine("Custom size PDF generated successfully")
End Using
End Using
End Function
End Class
After (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");
}
}
Imports System
Imports IronPdf
Imports IronPdf.Rendering
Module IronPdfCustomSize
Sub Main()
Dim renderer As New ChromePdfRenderer()
renderer.RenderingOptions.PaperSize = PdfPaperSize.Letter
renderer.RenderingOptions.MarginTop = 50
renderer.RenderingOptions.MarginBottom = 50
Dim html As String = "<html><body><h1>Custom Size PDF</h1></body></html>"
Dim pdf = renderer.RenderHtmlAsPdf(html)
pdf.SaveAs("custom-size.pdf")
Console.WriteLine("Custom size PDF generated successfully")
End Sub
End Module
Gotenberg requires string-based parameters ("8.5", "11", "0.5") added to multipart form data—no type safety, no IntelliSense, easy to mistype. IronPDF provides strongly-typed properties with PdfPaperSize enums and numeric margin values. Note that IronPDF margins are in millimeters (50mm ≈ 2 inches), while Gotenberg uses inches.
Critical Migration Notes
Unit Conversions
The most important conversion in this Gotenberg migration is the margin units:
// Gotenberg: margins in inches
content.Add(new StringContent("0.5"), "marginTop"); // 0.5 inches
content.Add(new StringContent("1"), "marginBottom"); // 1 inch
// IronPDF: margins in millimeters
renderer.RenderingOptions.MarginTop = 12.7; // 0.5 inches × 25.4 = 12.7mm
renderer.RenderingOptions.MarginBottom = 25.4; // 1 inch × 25.4 = 25.4mm
// Gotenberg: margins in inches
content.Add(new StringContent("0.5"), "marginTop"); // 0.5 inches
content.Add(new StringContent("1"), "marginBottom"); // 1 inch
// IronPDF: margins in millimeters
renderer.RenderingOptions.MarginTop = 12.7; // 0.5 inches × 25.4 = 12.7mm
renderer.RenderingOptions.MarginBottom = 25.4; // 1 inch × 25.4 = 25.4mm
' Gotenberg: margins in inches
content.Add(New StringContent("0.5"), "marginTop") ' 0.5 inches
content.Add(New StringContent("1"), "marginBottom") ' 1 inch
' IronPDF: margins in millimeters
renderer.RenderingOptions.MarginTop = 12.7 ' 0.5 inches × 25.4 = 12.7mm
renderer.RenderingOptions.MarginBottom = 25.4 ' 1 inch × 25.4 = 25.4mm
Conversion formula: millimeters = inches × 25.4
Synchronous vs Asynchronous
Gotenberg requires async operations because of HTTP communication:
// Gotenberg: Forced async due to network calls
var response = await client.PostAsync(gotenbergUrl, content);
var pdfBytes = await response.Content.ReadAsByteArrayAsync();
// IronPDF: Synchronous in-process execution
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("output.pdf");
// IronPDF: Async wrapper if needed
var pdf = await Task.Run(() => renderer.RenderHtmlAsPdf(html));
// Gotenberg: Forced async due to network calls
var response = await client.PostAsync(gotenbergUrl, content);
var pdfBytes = await response.Content.ReadAsByteArrayAsync();
// IronPDF: Synchronous in-process execution
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("output.pdf");
// IronPDF: Async wrapper if needed
var pdf = await Task.Run(() => renderer.RenderHtmlAsPdf(html));
Imports System.Net.Http
' Gotenberg: Forced async due to network calls
Dim response = Await client.PostAsync(gotenbergUrl, content)
Dim pdfBytes = Await response.Content.ReadAsByteArrayAsync()
' IronPDF: Synchronous in-process execution
Dim pdf = renderer.RenderHtmlAsPdf(html)
pdf.SaveAs("output.pdf")
' IronPDF: Async wrapper if needed
Dim pdf = Await Task.Run(Function() renderer.RenderHtmlAsPdf(html))
Error Handling
// Gotenberg: HTTP error handling
try
{
var response = await client.PostAsync(gotenbergUrl, content);
response.EnsureSuccessStatusCode(); // What if 500? 503? Timeout?
}
catch (HttpRequestException ex) { /* Network error */ }
catch (TaskCanceledException ex) { /* Timeout */ }
// IronPDF: Standard .NET exceptions
try
{
var pdf = renderer.RenderHtmlAsPdf(html);
}
catch (Exception ex)
{
Console.WriteLine($"PDF generation failed: {ex.Message}");
}
// Gotenberg: HTTP error handling
try
{
var response = await client.PostAsync(gotenbergUrl, content);
response.EnsureSuccessStatusCode(); // What if 500? 503? Timeout?
}
catch (HttpRequestException ex) { /* Network error */ }
catch (TaskCanceledException ex) { /* Timeout */ }
// IronPDF: Standard .NET exceptions
try
{
var pdf = renderer.RenderHtmlAsPdf(html);
}
catch (Exception ex)
{
Console.WriteLine($"PDF generation failed: {ex.Message}");
}
Imports System
Imports System.Net.Http
Imports System.Threading.Tasks
' Gotenberg: HTTP error handling
Try
Dim response = Await client.PostAsync(gotenbergUrl, content)
response.EnsureSuccessStatusCode() ' What if 500? 503? Timeout?
Catch ex As HttpRequestException
' Network error
Catch ex As TaskCanceledException
' Timeout
End Try
' IronPDF: Standard .NET exceptions
Try
Dim pdf = renderer.RenderHtmlAsPdf(html)
Catch ex As Exception
Console.WriteLine($"PDF generation failed: {ex.Message}")
End Try
Infrastructure Removal
After migration, remove Gotenberg from your infrastructure:
# REMOVE from docker-compose.yml:
# services:
# gotenberg:
# image: gotenberg/gotenberg:8
# ports:
# - "3000:3000"
# deploy:
# resources:
# limits:
# memory: 2G
# REMOVE from docker-compose.yml:
# services:
# gotenberg:
# image: gotenberg/gotenberg:8
# ports:
# - "3000:3000"
# deploy:
# resources:
# limits:
# memory: 2G
Performance Considerations
Latency Comparison
| Operation | Gotenberg (Warm) | 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 |
Infrastructure Cost Elimination
| Resource | Gotenberg | IronPDF |
|---|---|---|
| Containers required | 1-N (scaling) | 0 |
| Memory per container | 512MB-2GB | N/A |
| Network overhead per request | 10-100ms | 0ms |
| Health check endpoints | Required | Not needed |
| Load balancer | Often needed | Not needed |
Troubleshooting
Issue 1: HttpClient Patterns Not Needed
Problem: Code still using HttpClient and MultipartFormDataContent.
Solution: Replace entirely with ChromePdfRenderer:
// Remove all of this:
// using var client = new HttpClient();
// using var content = new MultipartFormDataContent();
// content.Add(new StringContent(html), "files", "index.html");
// var response = await client.PostAsync(url, content);
// Replace with:
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf(html);
// Remove all of this:
// using var client = new HttpClient();
// using var content = new MultipartFormDataContent();
// content.Add(new StringContent(html), "files", "index.html");
// var response = await client.PostAsync(url, content);
// Replace with:
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf(html);
Dim renderer As New ChromePdfRenderer()
Dim pdf = renderer.RenderHtmlAsPdf(html)
Issue 2: Margin Units Wrong
Problem: PDFs have incorrect margins after migration.
Solution: Convert inches to millimeters:
// Gotenberg used inches: "0.5"
// IronPDF uses millimeters: 0.5 × 25.4 = 12.7
renderer.RenderingOptions.MarginTop = 12.7;
// Gotenberg used inches: "0.5"
// IronPDF uses millimeters: 0.5 × 25.4 = 12.7
renderer.RenderingOptions.MarginTop = 12.7;
Issue 3: Container URL References
Problem: Code contains http://gotenberg:3000 or similar URLs.
Solution: Remove all container URL references—IronPDF runs in-process:
// Remove:
// private readonly string _gotenbergUrl = "http://gotenberg:3000";
// IronPDF needs no URL - it's in-process
var renderer = new ChromePdfRenderer();
// Remove:
// private readonly string _gotenbergUrl = "http://gotenberg:3000";
// IronPDF needs no URL - it's in-process
var renderer = new ChromePdfRenderer();
' Remove:
' Private ReadOnly _gotenbergUrl As String = "http://gotenberg:3000"
' IronPDF needs no URL - it's in-process
Dim renderer As New ChromePdfRenderer()
Migration Checklist
Pre-Migration
- Inventory all Gotenberg HTTP calls in codebase
- Document current Gotenberg configuration (timeouts, margins, paper sizes)
- Identify all Docker/Kubernetes Gotenberg configuration
- Obtain IronPDF license key
- Plan infrastructure decommissioning
Code Migration
- Install IronPDF NuGet package:
dotnet add package IronPdf - Remove Gotenberg client packages
- Replace all HTTP calls to Gotenberg with IronPDF method calls
- Convert margin units from inches to millimeters
- Update error handling (HTTP errors → .NET exceptions)
- Add license key initialization at startup
Infrastructure Migration
- Remove Gotenberg from Docker Compose / Kubernetes
- Update CI/CD pipelines (remove Gotenberg image pulls)
- Remove Gotenberg health checks
- Remove Gotenberg URL from configuration
Testing
- Test HTML to PDF conversion
- Test URL to PDF conversion
- Verify margin and sizing accuracy
- Performance test under load
- Test first-render warmup time
Post-Migration
- Remove Gotenberg container deployments
- Archive Gotenberg configuration files
- Update documentation
- Monitor application memory usage
- Verify no orphaned network connections

