A factual comparison of two self-hosted document conversion APIs: public benchmark, features, API equivalents in cURL, Node.js and Python, and a step-by-step migration guide.
Carbone or Gotenberg: which one should you choose?
Gotenberg and Carbone overlap on HTML and Office to PDF conversion, but they are built for different jobs. Pick the one that matches what you actually need to produce.
Choose Gotenberg if...
You only need HTML or Office to PDF and you already render the HTML yourself.
You need URL to PDF or page screenshots out of the box.
Your HTML needs JavaScript to render (client-side charts, single-page apps): Carbone disables JavaScript in Chrome for security, so it only converts HTML that is already rendered.
You need a toolbox for existing PDFs: merge, split, rotate, flatten, stamp, bookmarks, Factur-X.
You require an MIT license and your volumes are modest.
Choose Carbone if...
You need throughput: parallel Chromium, LibreOffice and Carbone ICE workers, 47.0x more HTML to PDF conversions per second in the benchmark.
You generate documents from data: a JSON payload and a DOCX, XLSX, PPTX, ODT, HTML or Markdown template, merged and converted in the same call.
You need formats beyond PDF: DOCX, XLSX, ODT, CSV, Markdown, PNG, WebP and 100+ more.
You want production features built in: converter hardening, OnlyOffice engine, template storage, a visual Studio, HA cluster, or a managed EU Cloud API.
Carbone vs Gotenberg benchmark
Carbone published an open-source benchmark of free document converters, with the scripts, sample files and Docker commands needed to reproduce it: carboneio/document-converter-benchmark. Here are the Carbone and Gotenberg results, in requests per second (higher is better).
HTML to PDF (Chromium)
Carbone 4 threads626.1 req/s
Carbone 1 thread272.5 req/s
Gotenberg 4 threads13.3 req/s
Gotenberg 1 thread10.4 req/s
DOCX to PDF (LibreOffice)
Carbone 4 threads99.9 req/s
Carbone 1 thread29.3 req/s
Gotenberg 1 thread12.4 req/s
DOCX to PDF (Carbone ICE)
Carbone 4 threads280.5 req/s
Carbone 1 thread96.5 req/s
Tool
Conversion
Threads
Avg latency
Requests per second
Carbone
HTML to PDF (Chromium)
4
7.74 ms
626.12
Carbone
DOCX to PDF (Carbone ICE)
4
16.96 ms
280.52
Carbone
HTML to PDF (Chromium)
1
18.03 ms
272.48
Carbone
DOCX to PDF (LibreOffice)
4
49.07 ms
99.87
Carbone
DOCX to PDF (Carbone ICE)
1
50.76 ms
96.48
Carbone
DOCX to PDF (LibreOffice)
1
169.21 ms
29.31
Gotenberg
HTML to PDF (Chromium)
4
374.74 ms
13.32
Gotenberg
DOCX to PDF (LibreOffice)
1
400.58 ms
12.44
Gotenberg
HTML to PDF (Chromium)
1
478.42 ms
10.41
HTML to PDF: with 4 threads, Carbone answers in 7.74 ms on average against 374.74 ms for Gotenberg, which is 47.0x more requests per second. With a single thread the gap is 26.2x.
DOCX to PDF with LibreOffice on both sides: on one thread, Carbone serves 2.4x more requests per second (29.31 against 12.44). Gotenberg runs a single LibreOffice process per container (its documentation recommends adding containers to scale), while one Carbone container with 4 threads reaches 99.87 requests per second, 8.0x a Gotenberg container.
DOCX to PDF with Carbone ICE: the converter built into Carbone, with no office suite involved, serves 96.48 requests per second on one thread (7.8x Gotenberg) and 280.52 with 4 threads.
Carbone does slightly more work than a pure converter: it also scans every document for Carbone tags before converting it.
Feature comparison
What each tool supports out of the box, based on the Carbone 5 and Gotenberg 8 documentation.
Both tools run as a local Docker container. The examples below target self-hosted instances: Gotenberg on port 3000 with multipart forms, Carbone on port 4000 with a JSON body where the file is encoded in base64.
HTML to PDF
Gotenberg expects a file named index.html. Carbone accepts any file name and uses its Chromium engine when converter is "C". Send a complete page with its <html> element: Carbone detects the file type from its content, and reads a fragment like <h1>Hello</h1> as XML.
Gotenberg cURL
curl --request POST http://localhost:3000/forms/chromium/convert/html \
--form files=@index.html \
--output result.pdf
The same request works for DOCX, XLSX, PPTX, ODT, ODS, ODP and RTF. With Carbone, "converter": "L" uses LibreOffice; "O" switches to OnlyOffice and "I" to Carbone ICE, the fastest engine for DOCX and ODT.
Gotenberg cURL
curl --request POST http://localhost:3000/forms/libreoffice/convert \
--form files=@document.docx \
--output result.pdf
Gotenberg renders Markdown through an index.html wrapper that calls {{ toHTML "document.md" }}. Carbone converts the Markdown file directly, and the same call can output DOCX or HTML instead of PDF.
Gotenberg reads page settings from form fields and separate header.html and footer.html files. Carbone reads them from custom elements placed inside the HTML itself, so the request body doesn't change.
<!-- index.html, sent with the same request as above ("converter": "C") --><!DOCTYPE html><html><body><carbone-pdf-optionspaper-size="A4"landscape="true"margin-top="1"margin-bottom="1" /><carbone-pdf-header><divstyle="font-size: 10px; width: 100%; text-align: center;">ACME Corp.</div></carbone-pdf-header><carbone-pdf-footer><divstyle="font-size: 10px; width: 100%; text-align: center;">
Page <spanclass="pageNumber"></span> of <spanclass="totalPages"></span></div></carbone-pdf-footer><h1>Quarterly report</h1></body></html>
Gotenberg has a dedicated merge route. Carbone merges PDFs while generating a document: the :appendFile formatter appends PDF files, given as URLs or base64 data URIs, at the end of the rendered template. This is an Enterprise feature, included in every Carbone Cloud plan.
To merge many documents generated from the same template, use batch generation with "batchOutput": "pdf". It is included in Carbone Cloud. When self-hosted, it requires the Enterprise Edition and CARBONE_NB_REPORT_MAX_PER_BATCH set to the maximum number of documents per batch.
Asynchronous conversion with a webhook
Both tools can answer immediately and call your server when the file is ready. Gotenberg replies 204 No Content, then posts the PDF to your webhook. Carbone posts a JSON object with a renderId, and you download the file with GET /render/{renderId}. Webhooks are available in every edition, including the free Community Edition. When self-hosted, Carbone refuses webhook URLs on a local network by default (see CARBONE_SECURITY_LEVEL).
This is where Carbone and Gotenberg differ most. With Gotenberg, you render the HTML with your own template engine before converting it. Carbone does both in one call: add {d.field} tags to an HTML, DOCX, XLSX, PPTX or Markdown file, and send your JSON in data.
Loops, conditions, number and date formatters, translations, charts and barcodes are described in the template design documentation.
How to migrate from Gotenberg to Carbone
Moving from Gotenberg to Carbone is mostly a matter of changing the URL and the request body. Run both side by side, compare the PDFs, then switch traffic.
1. Start Carbone next to Gotenberg
The full image ships LibreOffice, OnlyOffice and Chromium. Without a license key, it runs the free Community Edition.
docker run --rm -p 4000:4000 -e CARBONE_FACTORIES=4 carbone/carbone-ee:full
2. Replace each Gotenberg route with a single endpoint
Every conversion goes through POST /render/template. The input file and the converter field replace the route.
Gotenberg route
Carbone equivalent
POST /forms/chromium/convert/html
HTML file, "converter": "C"
POST /forms/chromium/convert/url
Download the HTML first, then "converter": "C"
POST /forms/chromium/convert/markdown
Markdown file, "converter": "L", no HTML wrapper
POST /forms/chromium/screenshot/html
HTML file, "convertTo": "png", "jpg" or "webp", without converter: LibreOffice renders the first page, not Chromium
POST /forms/libreoffice/convert
Office file, "converter": "L", "O" (OnlyOffice) or "I" (Carbone ICE)
POST /forms/pdfengines/convert
PDF file, "hardRefresh": true, SelectPdfVersion in formatOptions
POST /forms/pdfengines/encrypt
EncryptFile and DocumentOpenPassword in formatOptions
POST /forms/pdfengines/watermark
Watermark or Watermarks in formatOptions (text only)
POST /forms/pdfengines/merge
:appendFile in a template, or "batchOutput": "pdf"
POST /forms/pdfengines/embed, /forms/pdfengines/factur-x
:attachFile in a template
POST /forms/pdfengines/split, rotate, flatten, optimize, bookmarks
Noequivalent: keep Gotenberg or a PDF library for these steps
GET /health
GET /status
3. Send the file as base64 JSON instead of multipart
Read the file, encode it in base64 and put it in the template field, as in the API equivalents above. For pure conversion, don't send a data field: Carbone then converts the file as is.
4. Map your options
Gotenberg
Carbone
Where
paperWidth, paperHeight (US Letter by default)
paper-width, paper-height (inches) or paper-size="A4"
<carbone-pdf-header>, <carbone-pdf-footer> with pageNumber and totalPages
Inside the HTML
pdfa=PDF/A-2b, pdfua=true
"SelectPdfVersion": 2, "PDFUACompliance": true
convertTo.formatOptions
userPassword
"EncryptFile": true, "DocumentOpenPassword"
convertTo.formatOptions
watermarkSource=text, watermarkExpression
"Watermark", or "Watermarks" for size, color, opacity and angle
convertTo.formatOptions
Gotenberg-Webhook-Url
carbone-webhook-url
Request header
Gotenberg-Webhook-Extra-Http-Headers
carbone-webhook-header-X, one header per value
Request header
Gotenberg-Output-Filename
"reportName", sent with a data field ({} for a pure conversion)
Request body
--chromium-max-concurrency
CARBONE_FACTORIES or --factories
Server
--api-timeout (30 seconds by default)
CARBONE_MAX_GENERATION_TIME (60 seconds by default)
Server
5. Check which edition you need
Frequently asked questions
Is Carbone a drop-in replacement for Gotenberg?
For HTML, Office and Markdown to PDF, yes: Carbone runs as a Docker container like Gotenberg and uses Chromium and LibreOffice under the hood. The request format changes: one JSON endpoint (POST /render/template) with the file encoded in base64, instead of one multipart route per converter. Page options move into the HTML with <carbone-pdf-options>. URL to PDF, screenshots of URLs and the routes that edit existing PDFs (split, rotate, flatten, bookmarks) have no direct equivalent.
Is Carbone free like Gotenberg?
Gotenberg is free and MIT-licensed. The Carbone Community Edition is free to self-host and covers HTML, Office and Markdown conversion, PDF options, asynchronous webhooks and templating with text data. Enterprise features (appending PDFs, batch generation, charts, dynamic images, HA cluster) require a license when self-hosted, and every Carbone Cloud plan includes them, starting with a free plan.
Is Carbone faster than Gotenberg?
In the public benchmark published by Carbone (October 2026, Carbone 5.16.0 against Gotenberg 8.38.1, same files and hardware), Carbone served about 47 times more HTML to PDF conversions per second with 4 threads. For DOCX to PDF on one thread, Carbone served about 2.4 times more conversions per second when both tools use LibreOffice, and 7.8 times more with Carbone ICE, the converter built into Carbone. Gotenberg runs a single LibreOffice process per container, while Carbone runs several LibreOffice, Chromium or Carbone ICE workers in parallel. The scripts are open source, so you can reproduce the test on your own documents.
Can Carbone convert a URL to PDF?
No. Carbone converts the content you send, not web pages it fetches. Download the HTML of the page first, make its stylesheets and images absolute or inline, then convert it with the Chromium engine ("converter": "C"). If URL to PDF is your main need, Gotenberg handles it natively.
How do I merge PDFs with Carbone?
Use the :appendFile formatter in a template: each PDF given as a URL or a base64 data URI is appended to the generated document, for example a cover page followed by annexes. To combine many documents generated from the same template, use batch generation with "batchOutput": "pdf". Both are available in Carbone Cloud and in the self-hosted Enterprise Edition.
Can I generate PDF/A, PDF/UA, password-protected or watermarked PDFs?
Yes. Set SelectPdfVersion (PDF/A-1 to PDF/A-4), PDFUACompliance, EncryptFile with DocumentOpenPassword, and Watermark (or up to 4 styled Watermarks) in convertTo.formatOptions, in the same request as the conversion. PDF/A forbids encryption, so generate archival and password-protected copies separately. Image and PDF watermarks, which Gotenberg supports, are not available in Carbone.
What does Carbone do that Gotenberg doesn't?
Carbone is also a document generation engine: it fills DOCX, XLSX, PPTX, ODT, HTML and Markdown templates with JSON data (loops, conditions, formatters, translations, charts) and outputs PDF or 100+ other formats such as DOCX, XLSX, CSV or PNG. It also offers OnlyOffice and Carbone ICE engines, template storage, a visual Studio, official SDKs and a managed EU-hosted Cloud API.
Can I run Carbone and Gotenberg side by side during a migration?
Yes. Carbone listens on port 4000 by default and Gotenberg on port 3000, so both containers can run on the same host. Send the same documents to both, compare the PDFs, then switch your traffic route by route.