Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Gotenberg Pdf Bundle Laravel Package

rekalogika/gotenberg-pdf-bundle

A Symfony bundle that integrates Gotenberg, the Docker-powered PDF generation service, into your PHP app. Generate PDFs from HTML, URLs, or Markdown through a simple service or Twig, with configurable hosts, timeouts, and assets. Simplifies PDF creation without managing headless browsers yourself.

View on GitHub
Deep Wiki
Context7

Getting Started

First, the elephant in the room: this is a Symfony bundle, not a Laravel package. If you're a Laravel developer, you cannot composer require this and expect it to work — there's no ServiceProvider, no facade, no config publishing in Laravel's style. You have two honest options before going further:

  1. Target Symfony. Use this bundle in a Symfony app (6.x/7.x), which is what it's built for.
  2. Reach for the underlying library instead. The bundle is a thin Symfony DI wrapper around rekalogika/gotenberg-pdf. For Laravel, use that library directly, or use a Laravel-native alternative (e.g. spatie/laravel-pdf when it targets Gotenberg, or a direct Guzzle HTTP client against Gotenberg).

Assuming you're in a Symfony context, minimal steps:

  1. Run Gotenberg (it's a Docker sidecar, not a PHP library):

    docker run --rm -p 3000:3000 gotenberg/gotenberg:8
    

    Verify with curl http://localhost:3000/health.

  2. Require the bundle:

    composer require rekalogika/gotenberg-pdf-bundle
    
  3. Register it in config/bundles.php:

    Rekalogika\GotenbergPdfBundle\RekalogikaGotenbergPdfBundle::class => ['all' => true],
    
  4. Configure the Gotenberg endpoint in config/packages/rekalogika_gotenberg_pdf.yaml (verify the exact key against config/ in the repo — the vendor tree is authoritative):

    rekalogika_gotenberg_pdf:
      http_client: 'http://gotenberg:3000'
    
  5. Where to look first: read vendor/rekalogika/gotenberg-pdf-bundle/config/ for the service definitions and the src/ for the injected service interface. The public service you inject is your entry point (typically a GotenbergPdfInterface or a *Generator service — read the bundle's services.php to confirm the exact ID/alias).

First use case: convert an HTML string or URL to a PDF and stream it to the browser.

public function download(PdfGeneratorInterface $pdf): Response
{
    $result = $pdf->generateFromHtml('<h1>Hello</h1>');

    return new Response(
        $result->getStream(), // or getContent() depending on API
        200,
        ['Content-Type' => 'application/pdf']
    );
}

Implementation Patterns

Inject, don't instantiate. The value of the bundle is the DI wiring — the HTTP client (PSR-18), the Gotenberg base URI, and any options are configured once and injected. Never hand-roll a Guzzle client against Gotenberg inside your controller; you'll lose timeouts, retries, and config.

HTML → PDF is the primary path. Typical call center is:

  • render a Twig template to a string,
  • hand that string to the Gotenberg service,
  • get a stream/content back.
$html = $this->renderView('pdf/invoice.html.twig', ['invoice' => $invoice]);
$stream = $pdf->generateFromHtml($html, /* options */);

Options are passed per-call but configured for defaults. Gotenberg itself accepts a rich set of options (paper size, margins, header/footer HTML, wait-for-selector, print background, scale, etc.). The bundle exposes these — check the options DTO/array shape in src/. The pattern to adopt:

  • Set sane defaults once (either in YAML or a small factory/service you own).
  • Override per-document only what differs.

Treat Gotenberg as an external service for observability. Wrap calls in your application's error handling. Gotenberg failures are HTTP failures — a 400 means your HTML/options are bad, a 5xx/timeout means the container is struggling. Log the response body on failure; Gotenberg returns useful diagnostics.

Streaming vs. buffering. For large PDFs, prefer streaming to avoid loading the whole document in PHP memory. The underlying HTTP response is a stream — decide early whether you pipe it straight to the browser, store it via Flysystem, or return it. Don't buffer if you can stream.

Common integration shape for an app:

  • A PdfRenderer application service wrapping the bundle's service.
  • Twig templates for document layout.
  • A queue job for heavy generations (see gotchas — long-running conversions shouldn't block HTTP).
  • Storage + signed URL for delivery if documents are large or reused.

Gotchas and Tips

This is Symfony, not Laravel — the biggest gotcha. No config/pdf.php publishing, no facade, no container auto-discovery conventions Laravel devs assume. If your goal is a Laravel app, evaluate rekalogika/gotenberg-pdf (the library) or a Laravel package directly; don't fight the bundle.

Gotenberg must be reachable from PHP, not from the browser. In Docker Compose this means two containers with the service name as host (http://gotenberg:3000), not localhost — localhost inside the PHP container is the PHP container. This is the single most common "it hangs / connection refused" cause. Health-check Gotenberg before debugging your code.

Version pinning matters. Gotenberg's own API changes between major versions (v7 vs v8), and the library targets specific versions. Pin the Docker image tag (gotenberg/gotenberg:8) to match what the library expects, and pin the library version in Composer. Silent API drift will surface as 400s with cryptic messages.

Low-star, early-stage project — verify the API before you build on it. With ~11 stars, expect naming churn. Read src/ and config/ in vendor/ rather than trusting docs or blog posts. Lock the Composer version and treat upgrades as deliberate events with a test suite around PDF generation.

Long conversions block the worker. Gotenberg renders synchronously from PHP's perspective. Complex documents (large images, external assets, JS-heavy HTML) can take seconds. Push generation to Messenger/queue for anything user-facing that isn't instant-feedback.

External assets fail silently by default. If your HTML references images/CSS by URL, Gotenberg must be able to fetch them. Gotenberg has options like --gotenberg-download-from / allowlist configuration that must permit your hosts. A PDF that "renders" but is blank-styled is almost always this — check the Gotenberg container's outbound access and its downloadFrom config.

Timeouts are two-sided. Set both the HTTP client timeout (Symfony framework.http_client) and Gotenberg's own --api-timeout. A PHP timeout shorter than Gotenberg's means you abandon a render that's still running, wasting container resources.

Fonts. Non-Latin scripts and custom fonts require them to be present in the Gotenberg container or available via @font-face URLs it can fetch. This is an infrastructure concern, not a bundle one, but it bites every project eventually — build a custom Gotenberg image with fonts baked in.

Debugging strategy, in order: curl the Gotenberg /health; curl a minimal /forms/chromium/convert/html request directly against the container with your HTML; only then debug the PHP layer. If raw Gotenberg works but the bundle doesn't, the problem is options or the injected base URI — dump the resolved config from the container (bin/console debug:container, bin/console config:dump rekalogika_gotenberg_pdf).

Extension points to know: the bundle wires a PSR-18 HTTP client — you can swap it (e.g. for one with retries/logging) via service decoration or override. Options are typically a value object/array you can construct in a custom service; if you need per-tenant behaviour, decorate the generator rather than editing vendor config.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core