Skip to footer content
MIGRATION GUIDES

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:

  1. Infrastructure Overhead: Requires Docker, container orchestration (Kubernetes/Docker Compose), service discovery, and load balancing. Every deployment becomes more complex.

  2. 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.

  3. 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.

  4. Operational Complexity: You must manage container health, scaling, logging, and monitoring as separate concerns from your main application.

  5. Multipart Form Data: Every request requires constructing multipart/form-data payloads—verbose, error-prone, and tedious to maintain.

  6. Failure Points: Network timeouts, service unavailability, and container crashes all become your responsibility to handle.

  7. 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

  1. .NET Version: IronPDF supports .NET Framework 4.6.2+ and .NET Core 3.1+ / .NET 5/6/7/8/9+
  2. License Key: Obtain your IronPDF license key from ironpdf.com
  3. 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" .
SHELL

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
SHELL

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"
$vbLabelText   $csharpLabel

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"
$vbLabelText   $csharpLabel

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
$vbLabelText   $csharpLabel

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
$vbLabelText   $csharpLabel

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
$vbLabelText   $csharpLabel

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
$vbLabelText   $csharpLabel

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
$vbLabelText   $csharpLabel

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
$vbLabelText   $csharpLabel

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
$vbLabelText   $csharpLabel

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
$vbLabelText   $csharpLabel

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))
$vbLabelText   $csharpLabel

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
$vbLabelText   $csharpLabel

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
YAML

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)
$vbLabelText   $csharpLabel

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;
$vbLabelText   $csharpLabel

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()
$vbLabelText   $csharpLabel

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

Curtis Chau
Technical Writer

Curtis Chau holds a Bachelor’s degree in Computer Science (Carleton University) and specializes in front-end development with expertise in Node.js, TypeScript, JavaScript, and React. Passionate about crafting intuitive and aesthetically pleasing user interfaces, Curtis enjoys working with modern frameworks and creating well-structured, visually appealing manuals.

...

Read More

Iron Support Team

We're online 24 hours, 5 days a week.
Chat
Email
Call Me