Skip to content

NextPDF Gotenberg in production

The bridge makes one synchronous Hypertext Transfer Protocol (HTTP) round trip and validates the result. It does not retry, queue, cache, or rate-limit. Put those behaviors in the application around the bridge. This page shows what belongs where, and what the bridge guarantees, so you can build the rest correctly.

Treat every conversion as a remote call to a service you operate but do not control in-process. Plan for its latency and its failures.

GotenbergConfig stores the Uniform Resource Locator (URL) for the application programming interface (API) and, when authentication is enabled, a bearer token. The token field is marked #[\SensitiveParameter], so stack traces redact it. You are still responsible for sourcing it securely.

  • Load the token from your secret manager or from an injected environment value at process start. Do not commit it, and do not put it in a config file that ships in the image.
  • Build the config once per request scope or once per worker, not per conversion. The config is immutable and cheap to keep.
  • GotenbergConfig::fromArray() accepts malformed input by design and silently substitutes defaults. In production, validate the source array before you call fromArray(). A missing URL then appears as a configuration error during boot, not later as a per-conversion Invalid Gotenberg configuration: apiUrl is empty exception.

timeout (seconds, default 30) is the hard transfer timeout applied by the cURL-pinned transport. Office conversion through LibreOffice is not instant; large or complex documents take longer. Set the timeout from measured conversion latency for your real documents, with headroom. Keep it below any upstream gateway timeout or the PHP runtime’s max_execution_time. That lets the bridge time out first, with a typed exception instead of a killed process.

If you use the injected PHP Standard Recommendation 18 (PSR-18) client path (no responseFactory injected, or a bare Internet Protocol (IP) URL with no pins), the bridge does not apply the timeout value to that client. Configure the timeout on the PSR-18 client too, so both transports stay bounded.

The bridge sends exactly one request per call and never retries. Add retries in the caller, and make them safe:

  • Retry only transport-level failures (a GotenbergConvertException whose cause is a PSR-18 client exception) and idempotent server errors (HTTP 502, 503, 504). Do not retry every GotenbergConvertException indiscriminately. A 400-class response usually means the input is wrong, so the same retry will fail the same way.
  • Use bounded exponential backoff with jitter. When a conversion service under load returns 503, hammering it makes the outage worse.
  • Cap total attempts and total wall time. Conversion is already slow, so unbounded retries multiply tail latency.
  • Re-validation runs automatically: each retried call re-runs URL validation and the address re-check, so a retry cannot accidentally bypass the server-side request forgery (SSRF) guard.

Each conversion holds one connection and one LibreOffice worker on the Gotenberg side until the request finishes. The bridge itself is stateless and safe to use from many workers at the same time. The Gotenberg service still has finite conversion capacity.

  • Bound the number of in-flight conversions on your side (with a queue, a semaphore, or a worker pool) to the capacity Gotenberg can sustain. Sizing depends on your Gotenberg deployment, not on this package; see /integrations/gotenberg/security-and-operations/.
  • The input size cap (maxFileSize, default 50 MiB) is the bridge’s only built-in resource bound. The bridge enforces it in-process before the request is sent, so an oversized file never consumes service capacity. Lower it to match what your documents actually need; a smaller cap is a cheaper denial-of-service control than a larger one.
  • There is no in-process caching. If you convert the same document repeatedly, cache the resulting Portable Document Format (PDF) in your application, keyed by a content hash of the input.

Inject a PHP Standard Recommendation 3 (PSR-3) logger to get one debug entry for each conversion request. The entry contains the request URL, the file name, the detected format, and the request content length. It does not contain file contents or the bearer token.

  • Turn that signal into a metric: count conversions by format and outcome, and record the wall time around each convertFile() / convertString() call as a latency histogram. The bridge does not emit metrics itself.
  • The result object exposes a renderTimeMs field. It is 0.0 unless your integration measures and sets it; the bridge does not populate it from the Gotenberg response. Time the call yourself if you need the value.
  • Log exceptions with their type. The exception type is the primary signal for what failed; see /integrations/gotenberg/troubleshooting/ for the catalog.
  • Probe isAvailable() from your readiness or health endpoint, not on every conversion. It sends a HEAD to /health. Running it before each conversion doubles your request rate against the service for no benefit.

The bridge surfaces failures as typed exceptions and never returns a partial or unvalidated result. It guarantees the following:

  • A non-200 status, a Content-Type without application/pdf, or a body that does not begin with %PDF raises a GotenbergConvertException. The bridge returns a result object only when all three checks pass.
  • A PSR-18 client failure (including a network failure or timeout) is wrapped as a GotenbergConvertException, with the original exception as its cause and the client’s code as the exception code.
  • Validation failures (non-HTTPS URL, private/reserved address, oversized input, unsafe filename) raise RuntimeException before any network traffic.
  • An unrecognized file extension raises ValueError before any network traffic.

Catch the specific types. The example program in examples/convert-office-to-pdf.php shows the exhaustive catch order. /integrations/gotenberg/troubleshooting/ explains each trigger.

The bridge produces a PDF and stops. A common production pipeline is:

  1. Convert the Office document with this bridge.
  2. Load the resulting bytes into a NextPDF document.
  3. Apply post-processing: page assembly, watermarking, Portable Document Format/Archive (PDF/A) conversion, and digital signatures.

Step 3 belongs to NextPDF, not the bridge. nextpdf/premium provides signing, PDF/A profiles, and watermarking. Keep conversion and post-processing as separate stages, so you can diagnose a conversion failure independently from a signing failure.

The Pro edition’s PDF Advanced Electronic Signatures (PAdES) support is the B-B baseline only. It does not provide B-T, B-LT, or B-LTA, and those profiles are not implied by converting a document through this bridge. Long-term validation capability is a separate edition concern and is out of scope for this package.

  • /integrations/gotenberg/configuration/ - transport-selection rules and the pin model.
  • /integrations/gotenberg/security-and-operations/ - deploying and hardening the Gotenberg dependency.
  • /integrations/gotenberg/troubleshooting/ - the exception catalog.
  • /integrations/gotenberg/integration/ - connecting the converted PDF to a NextPDF pipeline.