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

Laravel Qrcode Laravel Package

akira/laravel-qrcode

Generate QR codes in Laravel with a simple facade and fluent API. Customize size, colors, margins, and error correction, then save, download, or embed codes in Blade views. Supports common image formats for flexible QR code output.

View on GitHub
Deep Wiki
Context7

Getting Started

composer require akira/laravel-qrcode

The package is auto-discovered — there is nothing to register in bootstrap/providers.php or config/app.php on Laravel 11/12. If the package ships a config file, publish it before you touch any defaults:

php artisan vendor:publish --tag="qrcode-config"

Where to look first, in this order:

  1. README.md — for a 49-star package the README is the API documentation. Read the full example block before writing anything; the fluent method names (size(), margin(), format(), errorCorrection()) are the contract.
  2. src/ — find the Facade and the class it points to. That class is the whole package. Read it end-to-end; it will be a few hundred lines wrapping an underlying QR library (bacon/bacon-qr-code, chillerlan/php-qrcode, or endroid/qr-code). Knowing which one is underneath tells you what options actually exist.
  3. composer.json — check the require block for ext-imagick / ext-gd and the PHP/Laravel constraints. This is the single most common source of "works locally, breaks in CI" pain.
  4. tests/ — the fastest way to learn the intended usage is to read the assertions; they show the exact return types (string of bytes? Response? DataUri object?).

First use case — an invoice/receipt page that renders a scannable link to a public verification URL:

use Akira\QrCode\Facades\QrCode;

public function show(Invoice $invoice)
{
    $png = QrCode::format('png')
        ->size(300)
        ->margin(2)
        ->generate(route('invoices.verify', $invoice));

    return response($png, 200, ['Content-Type' => 'image/png']);
}

Get that one endpoint working before you build abstractions. Generate, dump the bytes to a file, and scan it with your phone — that closes the loop on encoding, quiet zone, and contrast in about two minutes.

Implementation Patterns

Data URI for embedding (the highest-value pattern). Writing PNGs to storage/ and cleaning them up is the usual anti-pattern for this kind of package. Inline them instead — it works identically in Blade, PDF renderers, and email:

$dataUri = 'data:image/png;base64,' . base64_encode(
    QrCode::format('png')->size(240)->generate($payload)
);
<img src="{{ $dataUri }}" alt="Scan to verify" width="240" height="240">

SVG for print and PDFs. If the output goes into dompdf, Snappy, or anything destined for paper, use SVG. It is resolution-independent, avoids the GD/Imagick dependency entirely, and produces smaller payloads for short data:

QrCode::format('svg')->size(600)->generate($url);

Download responses. Return the bytes with a filename rather than streaming a temp file:

return response(QrCode::format('png')->size(512)->generate($url), 200, [
    'Content-Type'        => 'image/png',
    'Content-Disposition' => 'attachment; filename="ticket-' . $ticket->id . '.png"',
]);

Cache the bytes, not the object. QR generation is cheap but not free, and a ticket page hit 500 times shouldn't regenerate 500 times. Key on a hash of payload plus the options that affect the matrix:

$key = 'qr:' . hash('xxh128', $url . '|png|300|2|M');

$png = Cache::remember($key, now()->addDay(), fn () => QrCode::format('png')
    ->size(300)->margin(2)->generate($url));

If you change the size or error-correction level, the key must change too — otherwise you serve a cached image at the wrong dimensions.

Wrap it behind your own service. With 49 stars and zero dependents, the package is a thin convenience layer over a mature QR library. Put it behind a single class so swapping to endroid/qr-code or bacon/bacon-qr-code later is a one-file change:

final class QrCodeGenerator
{
    public function png(string $payload, int $size = 300): string
    {
        return QrCode::format('png')->size($size)->margin(2)->generate($payload);
    }
}

Inject that, never the facade, in controllers and jobs.

Bulk generation belongs in a job. Generating 200 badge QR codes inside a web request will time out on shared hosting. Fan out to a queued job per batch, write to disk once, zip, then notify.

Testing. Never snapshot the binary image — a dependency bump on the underlying renderer changes bytes and your suite goes red for no reason. Assert on the response Content-Type, strlen() > 0, and the payload you passed in. Store a known-good QR as a fixture only if you actually need to catch a renderer regression.

Gotchas and Tips

The image extension is the #1 failure. ext-gd or ext-imagick is required for PNG/JPEG output. Your local Docker image has it; your production buildpack may not. Check composer.json, and if you can't guarantee the extension, standardize on SVG output — it needs neither.

Quiet zone is not optional. margin(0) produces QR codes that many phone scanners refuse because the spec requires a light border. Keep it at 2–4 modules. This is the most common "it works on my phone but not on the cheaper one" bug.

Never invert colours. Dark modules on a light background, always. ->color(255,255,255)->backgroundColor(0,0,0) looks striking and scans unreliably. Same for low-contrast brand colours — if you must theme it, darken the foreground, don't lighten it.

Payload length explodes the matrix. Error-correction level H (30% recovery) roughly quadruples module count versus L. A 300-character URL at H can produce a dense grid that fails on low-end scanners at small print sizes. For URLs, use M and shorten the URL (short link or a compact signed route) before increasing the physical size.

Encoding trips up non-ASCII. vCard payloads with accented names, emoji, or CJK text can garble depending on the underlying library's ECI handling. Test with a real accented string and scan it — don't assume UTF-8 passthrough.

config:cache bites if you use env(). If the package's config file calls env() directly and you've run php artisan config:cache, the values freeze. Publish the config and put real values in it rather than relying on .env lookups inside the package.

Facade method chaining may be stateful. Many of these wrappers return $this from the builder methods, meaning a resolved instance could carry options across calls if it's a singleton. If you generate two codes with different sizes in one request and the second comes out the wrong size, that's the cause — resolve a fresh builder or call a reset()/fresh() if one exists.

Version pin conservatively. Zero dependents means little community soak time. Pin with "akira/laravel-qrcode": "^1.0" rather than dev-main, and read the diff of any minor bump — small packages sometimes change fluent method signatures between releases.

Extension points to check for in src/: a config-driven default format/size (so you stop repeating ->size(300) everywhere), a binding you can override in a service provider to swap the underlying renderer, and whether the facade is Macroable (letting you add QrCode::vcard($contact) helpers application-wide). If none exist, your own QrCodeGenerator wrapper is the extension point — build it on day one, not after the first refactor.

Debugging checklist when a code won't scan: (1) open the generated file directly, not through your view; (2) check the payload round-trips through json_decode/parse_url intact; (3) confirm margin ≥ 2; (4) confirm foreground is darker than background; (5) generate at 2× the display size — CSS downscaling of a 150px image to 80px is a classic failure.

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.
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
nodisrupt/laravel-agent
sierratecnologia/media-manager