Laravel8 min read · June 5, 2026

Generating PDF Invoices in Laravel: A Complete Guide

Build a PDF invoice system in Laravel using Blade templates and the HTML to PDF API. Covers the template, controller, email attachment, and storage.

Invoice PDF generation is one of the most common requirements in Laravel apps — and one of the most frustrating to get right. The layout needs to look professional, the numbers need to be correct, and it needs to be downloadable, emailable, and storeable on demand.

This guide walks through a complete implementation: a Blade invoice template, a controller action that streams the PDF, and an email attachment — all using the HTML to PDF API so you don't need any server binaries.

The Blade Template

Start with a clean HTML invoice template. Use inline styles for maximum PDF compatibility:

resources/views/invoices/pdf.blade.phphtml
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <style>
    body  { font-family: sans-serif; font-size: 13px; color: #111; margin: 0; padding: 32px; }
    .header { display: flex; justify-content: space-between; margin-bottom: 40px; }
    .logo   { font-size: 22px; font-weight: 700; color: #2563eb; }
    table   { width: 100%; border-collapse: collapse; margin-top: 24px; }
    th, td  { padding: 10px 12px; border-bottom: 1px solid #e5e7eb; text-align: left; }
    th      { background: #f9fafb; font-weight: 600; }
    .total  { font-size: 16px; font-weight: 700; text-align: right; margin-top: 20px; }
  </style>
</head>
<body>
  <div class="header">
    <span class="logo">Acme Inc.</span>
    <div>
      <strong>Invoice #{{ $invoice->number }}</strong><br>
      Date: {{ $invoice->date->format('d M Y') }}
    </div>
  </div>

  <p>Bill to: <strong>{{ $invoice->customer->name }}</strong></p>

  <table>
    <thead>
      <tr><th>Description</th><th>Qty</th><th>Unit Price</th><th>Total</th></tr>
    </thead>
    <tbody>
      @foreach ($invoice->items as $item)
      <tr>
        <td>{{ $item->description }}</td>
        <td>{{ $item->quantity }}</td>
        <td>{{ money($item->unit_price) }}</td>
        <td>{{ money($item->total) }}</td>
      </tr>
      @endforeach
    </tbody>
  </table>

  <div class="total">Total: {{ money($invoice->total) }}</div>
</body>
</html>

The Controller

The controller renders the Blade view to HTML, sends it to the API, and streams the PDF response back:

app/Http/Controllers/InvoiceController.phpphp
<?php

namespace App\Http\Controllers;

use App\Models\Invoice;
use HtmlToPdfApi\Client;
use Illuminate\Http\Response;

class InvoiceController extends Controller
{
    public function __construct(private Client $pdf) {}

    public function download(Invoice $invoice): Response
    {
        $this->authorize('view', $invoice);

        $html = view('invoices.pdf', compact('invoice'))->render();

        $bytes = $this->pdf
            ->fromHtml($html)
            ->paperSize('a4')
            ->orientation('portrait')
            ->generate();

        return response($bytes, 200, [
            'Content-Type'        => 'application/pdf',
            'Content-Disposition' => 'attachment; filename="invoice-' . $invoice->number . '.pdf"',
        ]);
    }
}

Attaching to an Email

To attach the PDF to a Laravel Mailable, generate the bytes first and pass them to attachData:

app/Mail/InvoiceMail.phpphp
public function build(): self
{
    $html  = view('invoices.pdf', ['invoice' => $this->invoice])->render();
    $bytes = app(Client::class)->fromHtml($html)->generate();

    return $this->subject('Your Invoice #' . $this->invoice->number)
                ->view('emails.invoice')
                ->attachData($bytes, 'invoice.pdf', [
                    'mime' => 'application/pdf',
                ]);
}

Storing in S3

Need to store invoices for later retrieval? Use Laravel Storage to push the PDF bytes to S3 or any configured disk:

store snippetphp
Storage::disk('s3')->put(
    "invoices/{$invoice->number}.pdf",
    $bytes,
    ['ContentType' => 'application/pdf', 'ACL' => 'private']
);