Why Generate QR Codes in Laravel 11? (Use Cases & Benefits)
QR codes make it easy to share URLs, contact details, Wi-Fi credentials, payment links, or event info instantly. In Laravel 11, thesimplesoftwareio/simple-qrcode package (powered by BaconQrCode) lets you create dynamic QR codes on-the-fly and save them securely to server storage — perfect for tickets, invoices, marketing campaigns, or user profiles. This approach is fast, customizable, and requires no external API keys. 
Table Of Content
1 Prerequisites
- PHP ≥ 8.2
- Composer
- Fresh Laravel 11 project
2 Introduction: Generate & Save QR Codes in Laravel 11 – Complete 2025 Guide
Whether you're building a marketing campaign, customer loyalty system, event registration flow, invoice generator, or contactless business card feature, being able to dynamically generate QR codes in Laravel 11 and save the QR code images directly to your server is an extremely valuable skill.
In this step-by-step Laravel 11 tutorial you will learn how to:
- Install and configure the most popular and actively maintained QR code package
- Create different types of QR codes (URL, plain text, phone, SMS, email, vCard / digital business card, Wi-Fi, and more)
- Customize appearance (size, color, error correction level, margin, rounded edges…)
- Save generated QR code images securely to Laravel storage (public disk + downloadable links)
- Display the QR code instantly on the page with a download button
- Build a clean, user-friendly form that changes fields depending on the selected QR type
By the end of this guide, you’ll have a fully working Laravel 11 QR code generator that stores images on the server — ready to be used in real projects or extended with logo embedding, SVG support, analytics tracking, and more.
Let’s get started!
3 Install Laravel Project
composer create-project laravel/laravel laravel-qr-generator
Then, navigate to your project directory:
cd laravel-qr-generator
4 Install the Simple QR Code Package
composer require simplesoftwareio/simple-qrcode
The package auto-registers in Laravel 11 (no need to edit config/app.php).
5 Generate QR Code Examples
1.URL
Specify the website URL including the protocol (HTTP or HTTPS) to recognize the QR code as a URL.
$qrContent = 'https://getsamplecode.com/';
2.TEXT:Specify the Text to Generate QR Code.
$qrContent = 'QR Code Generated by GetSampleCode';
3.Phone NumberSpecify the Phone Number including Country Code to Generate QR Code.
$qrContent = 'tel:+16471234567';
4.SMSSpecify the Phone Number including Country Code and pre filled message to Generate QR Code.
$qrContent = 'sms:+16471234567:Samplemessage';
5.EMAILSpecify the Email Address to Generate QR Code.
$qrContent = ''mailto:getsamplecode@gmail.com';';
6 Create the QR Code Controller
php artisan make:controller QrCodeController
In the controller, you can define methods for displaying and generating QR codes dynamically based on user input. This allows for flexibility in generating QR codes for URLs, texts, phone numbers, and more.
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use SimpleSoftwareIO\QrCode\Facades\QrCode;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
class QrCodeController extends Controller
{
public function index()
{
return view('qrcode');
}
public function generate(Request $request)
{
$request->validate([
'qrcode_type' => 'required|integer|between:1,8',
// Add more specific validation per type if needed
]);
$data = '';
$type = $request->qrcode_type;
if (in_array($type, [1, 2])) {
$data = $request->qr_code_content;
} elseif ($type == 3) {
$data = 'tel:' . $request->qr_phone_number;
} elseif ($type == 4) {
$data = 'sms:' . $request->qr_sms_phone_number . ':' . $request->qr_sms_message;
} elseif ($type == 5) {
$data = 'mailto:' . $request->qr_email_email_id;
} elseif ($type == 6) {
$data = 'mailto:' . $request->qr_email_extended_email_id .
'?subject=' . urlencode($request->qr_email_extended_subject) .
'&body=' . urlencode($request->qr_email_extended_message);
} elseif ($type == 7) {
$data = 'skype:' . urlencode($request->qr_skype_username) . '?call';
} elseif ($type == 8) {
$data = "BEGIN:VCARD\n" .
"VERSION:3.0\n" .
"N:{$request->qr_business_card_last_name}\n" .
"FN:{$request->qr_business_card_first_name}\n" .
"TEL;TYPE=cell:{$request->qr_business_card_phone}\n" .
"EMAIL:{$request->qr_business_card_email}\n" .
"ADR;TYPE=HOME;LABEL=\"{$request->qr_business_card_address}\"\n" .
"END:VCARD";
}
if (empty($data)) {
return back()->withErrors(['Invalid QR code data']);
}
// Unique filename using hash to avoid collisions
$filename = 'qrcodes/' . Str::random(40) . '.png';
// Generate QR code (customize size, margin, etc.)
$qrCode = QrCode::size(500)
->margin(4)
->errorCorrection('H') // High error correction for reliability
->generate($data);
// Save to storage (uncommented & fixed)
Storage::disk('public')->put($filename, $qrCode);
// Get public URL
$qrUrl = Storage::url($filename);
return view('qrcode', compact('qrCode', 'qrUrl', 'filename'));
}
}
?>
Notes:
- Added validation.
- Used public disk for easy access (run php artisan storage:link if not done).
- Unique filenames prevent overwrites.
- Added error correction level 'H'.
7 Create Qr Code Blade View File
Use Bootstrap for styling and JavaScript to show/hide fields. HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Generate QR Code - Laravel 11</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body class="bg-light">
<div class="container my-5">
<h1 class="text-center mb-4">Generate QR Codes in Laravel 11</h1>
@if (session('success'))
<div class="alert alert-success">{{ session('success') }}</div>
@endif
@if ($errors->any())
<div class="alert alert-danger">
<ul>
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif
<form action="{{ route('qr.generate') }}" method="POST" class="card p-4">
@csrf
<div class="mb-3">
<label for="qrcode_type" class="form-label">QR Code Type</label>
<select class="form-select" name="qrcode_type" id="qrcode_type" onchange="choose_content(this.value)" required>
<option value="">Select Type</option>
<option value="1">Text</option>
<option value="2">URL</option>
<option value="3">Phone Number</option>
<option value="4">SMS</option>
<option value="5">Email (Simple)</option>
<option value="6">Email (Extended)</option>
<option value="7">Skype Call</option>
<option value="8">Business Card (vCard)</option>
</select>
</div>
<!-- Conditional fields (use display: none/block via JS) -->
<div id="text_content" class="qr_content mb-3" style="display:none;">
<label class="form-label">Content</label>
<input type="text" name="qr_code_content" class="form-control" placeholder="Enter text or URL">
</div>
<!-- Add similar divs for phone, sms, email, etc. (as in original) -->
<button type="submit" class="btn btn-primary w-100">Generate QR Code</button>
</form>
@if (isset($qrCode))
<div class="text-center mt-5">
<h3>Your QR Code</h3>
{!! $qrCode !!}
<p><strong>Saved at:</strong> {{ $qrUrl ?? 'Not saved' }}</p>
@if (isset($qrUrl))
<a href="{{ $qrUrl }}" class="btn btn-success" download>Download QR Code</a>
@endif
</div>
@endif
</div>
<script>
function choose_content(id) {
document.querySelectorAll('.qr_content').forEach(el => el.style.display = 'none');
if (id == 1 || id == 2) document.getElementById('text_content').style.display = 'block';
// Add cases for other IDs...
}
</script>
</body>
</html>
8 Define a Route
use App\Http\Controllers\QrCodeController;
Route::get('/qr-code', [QrCodeController::class, 'index'])->name('qr.index');
Route::post('/generate-qrcode', [QrCodeController::class, 'generate'])->name('qr.generate');
9 Enable Public Storage (One-Time)
php artisan storage:link
Create storage/app/public/qrcodes folder if needed (or let Laravel create it). 10 Folder Structure
11 Run Laravel Server to Test the App
php artisan serve
Visit http://127.0.0.1:8000/qr-code
Advanced Customizations
- Change color: QrCode::color(0, 0, 255)
- Add logo: QrCode::merge('path/to/logo.png', .2)
- SVG output: QrCode::format('svg')
- Download as file: Add a route/controller to return Storage::download($filename)
12 Conclusion: Build Powerful QR Features in Laravel 11
Written by Revathi M
PHP Developer & Technical Writer · 10+ years building web applications with CodeIgniter and Laravel
Revathi specializes in PHP backend development, authentication systems, and REST API design. She writes practical, production-tested tutorials at Get Sample Code to help developers build secure applications faster.
Frequently Asked Questions
You need PHP 8.2 or higher, Composer, and a fresh Laravel 11 project.
Run `composer require simplesoftwareio/simple-qrcode`.
The `simplesoftwareio/simple-qrcode` package, which is a Laravel-friendly wrapper around BaconQrCode.
Run `php artisan make:controller QrCodeController`.
Use `QrCode::size(600)->margin(5)->generate($data);` where `$data` is the content (URL, text, etc.).
In the form, use a dropdown for `qrcode_type` and conditionally build the `$data` string (e.g., `mailto:...` for email, `tel:...` for phone).
Uncomment and use `Storage::disk('local')->put('qrcodes/' . $filename . '.png', $qrCode);`. Ensure the `qrcodes` folder exists in `storage/app`.
Use `php artisan storage:link` to create a symlink from `public/storage` to `storage/app/public`, and save to `storage/app/public/qrcodes/`.
The storage line is commented out in the blog example. Uncomment it, ensure the directory exists, and check write permissions.
In `routes/web.php`, change `use AppHttpControllersQRCodeController;` to match the actual controller name `QrCodeController`.
Install the PHP Imagick extension (`pecl install imagick` or via your package manager). Alternatively, the package falls back to GD if Imagick is unavailable.
Chain methods like `->size(300)->color(255,0,0)->backgroundColor(255,255,255)->style('dot')`. For logos, use `->merge('/path/to/logo.png', .3)`.
Output directly with `{{ $qrCode }}` for inline SVG/PNG, or provide a download link after storing the file.
Start the server with `php artisan serve`, then visit the route (e.g., `http://127.0.0.1:8000/index`).
