I’m always excited to take on new projects and collaborate with innovative teams to build impactful digital solutions.
Transform a slow Laravel 13 application into a lightning-fast one with these 50+ performance optimization techniques covering caching, database, queues, and deployment.
Performance is not optional. Studies show that a 100ms delay in load time can reduce conversion rates by 7%. In this comprehensive guide, we'll cover 50+ techniques to make your Laravel 13 application lightning fast - from caching strategies to database indexing and beyond.
Never guess where the bottleneck is. Use Laravel's built-in tools:
// Measure query time in tinker
DB::enableQueryLog();
User::all();
dd(DB::getQueryLog());
// Use Laravel Debugbar in development
composer require barryvdh/laravel-debugbar
PHP OPcache dramatically reduces CPU usage by caching compiled bytecode:
# php.ini
opcache.enable=1
opcache.memory_consumption=256
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=20000
opcache.revalidate_freq=2
opcache.validate_timestamps=0 # Production only
opcache.enable_cli=1
php artisan route:cache
php artisan config:cache
php artisan event:cache
php artisan view:cache
| Driver | Speed | Use Case |
|---|---|---|
| file | Slow | Development only |
| database | Slow | Shared hosting |
| redis | Fast | Recommended for production |
| memcached | Fast | Alternative to Redis |
| dynamodb | Fast | AWS environments |
// Simple cache
Cache::remember('posts.homepage', 3600, function () {
return Post::published()->with('author')->latest()->take(10)->get();
});
// Cache tags for related data
Cache::tags(['posts', 'homepage'])->remember('featured', 3600, fn() => [...]);
// Cache forever until invalidated
Cache::forever('config.settings', $settings);
// In validate when data changes
protected static function booted(): void
{
static::saved(function () {
Cache::forget('posts.homepage');
Cache::tags(['posts'])->flush();
});
}
// Or use observers
class PostObserver
{
public function saved(Post $post): void
{
Cache::forget('posts.homepage');
Cache::forget('post.' . $post->id);
}
}
Indexes are the single biggest database performance lever:
Schema::table('posts', function (Blueprint $table) {
$table->index(['status', 'published_at']); // Filtering
$table->index('author_id'); // FK lookups
$table->index('slug'); // URL lookups
$table->fullText(['title', 'content']); // Full-text search
});
// Composite index for multi-column queries
Schema::table('orders', function (Blueprint $table) {
$table->index(['user_id', 'status', 'created_at']);
});
// Find missing indexes with raw SQL
SELECT TABLE_NAME, COLUMN_NAME
FROM INFORMATION_SCHEMA.STATISTICS;
// Only fetch needed columns
$users = User::select('id', 'name', 'email')->get();
// Avoid COUNT(*) on large tables - use estimates
$count = DB::table('posts')->select(DB::raw('COUNT(*) as count'))->first()->count;
// Use latest() instead of orderBy('created_at', 'desc')
$posts = Post::latest()->get();
// Paginate, never use get() for lists
$posts = Post::paginate(20);
// Avoid N+1
$posts = Post::with(['author', 'comments.user'])->get();
// Use lazy loading intentionally
$posts->loadMissing('comments'); // Only loads if not already loaded
# .env
SESSION_DRIVER=redis
QUEUE_CONNECTION=redis
CACHE_STORE=redis
# Redis config with persistent connections
'redis' => [
'client' => env('REDIS_CLIENT', 'phpredis'),
'options' => [
'prefix' => env('REDIS_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_') . '_database_'),
],
],
Route::middleware(['cache.headers:public;max_age=3600;etag'])->group(function () {
Route::get('/blog', [BlogController::class, 'index']);
});
// Mix/Blade - use CDN URLs for assets
asset('build/app.js') // Serve via CDN in production
// Or use a service like CloudFlare for edge caching
// Use Intervention Image to resize on upload
use Intervention\Image\Facades\Image;
Image::make($file)
->resize(1200, 800, function ($constraint) {
$constraint->aspectRatio();
})
->save(public_path('storage/posts/' . $filename), 80); // 80% quality
// Serve WebP when supported
if (str_contains($request->header('Accept'), 'image/webp')) {
return response()->file($webpPath);
}
<img src="{{ asset('img/placeholder.webp') }}"
data-src="{{ asset('storage/posts/' . $post->image) }}"
loading="lazy"
class="lazyload"
alt="{{ $post->title }}">
<script>
// Use a tiny JS lazy loader or native loading="lazy"
</script>
// Send emails, process uploads, hit APIs - all in queues
class SendWelcomeEmail implements ShouldQueue
{
public function handle(): void
{
// Email sending happens in the background
}
}
SendWelcomeEmail::dispatch($user);
// Laravel 11+ persistent connections
'database' => [
'default' => env('DB_CONNECTION', 'mysql'),
'connections' => [
'mysql' => [
'driver' => 'mysql',
'persistent' => true, // Reuse connections
'pool' => ['min' => 5, 'max' => 100],
],
],
],
// Use Laravel's model::preventLazyLoading() in development
public function boot(): void
{
Model::preventLazyLoading(! app()->isProduction());
Model::preventSilentlyDiscardingAttributes(! app()->isProduction());
}
composer require laravel/octane
php artisan octane:install
# Start with RoadRunner
php artisan octane:start --server=roadrunner --host=127.0.0.1 --port=8000
# Or Swoole
php artisan octane:start --server=swoole --host=127.0.0.1 --port=8000
# Nginx proxy to Octane
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://127.0.0.1:8000;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
# nginx.conf - upstream with multiple app servers
upstream laravel_app {
least_conn;
server 10.0.0.1:8000;
server 10.0.0.2:8000;
server 10.0.0.3:8000;
}
server {
listen 80;
location / {
proxy_pass http://laravel_app;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
// Install Laravel Telescope
composer require laravel/telescope --dev
php artisan telescope:install
php artisan migrate
// Production monitoring with Laravel Pulse
composer require laravel/pulse
php artisan pulse:install
php artisan migrate
// Custom performance metrics
app('metrics')->timing('api.request', $duration, ['endpoint' => $request->path()]);
Applying these techniques typically yields:
Performance optimization is a continuous process, not a one-time task. Start with the quick wins (caching, indexing, eager loading), then move to architectural improvements (Octane, scaling). Measure every change, monitor continuously, and your Laravel 13 application will handle millions of requests effortlessly.
Your email address will not be published. Required fields are marked *