Toolmingo
Guides22 min read

50 Laravel Interview Questions (With Answers)

Top Laravel interview questions with clear answers and code examples — covering Eloquent ORM, routing, middleware, authentication, queues, testing, and deployment.

Laravel interviews test your command of Eloquent ORM, routing conventions, service container, authentication patterns, queue jobs, and testing. This guide covers 50 common questions — with concise answers and real code examples.

Quick reference

Topic Most asked questions
Architecture Service container, service providers, facades
Routing Route groups, middleware, model binding
Eloquent ORM Relationships, scopes, mutators, eager loading
Blade Directives, components, layouts
Authentication Sanctum, Breeze, Jetstream, gates/policies
API Development API resources, rate limiting, versioning
Queues & Jobs Dispatching, retry, horizon
Events & Listeners Event broadcasting, real-time
Testing PHPUnit, Pest, HTTP testing, mocking
Performance Caching, N+1 prevention, Octane

Architecture

1. What is Laravel's service container?

The service container (IoC container) resolves class dependencies automatically via reflection and binding.

// Binding in a service provider
$this->app->bind(PaymentGateway::class, StripeGateway::class);

// Automatic resolution — Laravel injects UserRepository via constructor
public function __construct(UserRepository $repo)
{
    $this->repo = $repo;
}

// Manual resolution
$gateway = app(PaymentGateway::class);

The container reads type hints and resolves the concrete class for you, enabling dependency injection throughout the framework.


2. What are service providers?

Service providers are the central place to bootstrap app components. Every provider has register() (bind things to the container) and boot() (code that runs after all providers are registered).

class AppServiceProvider extends ServiceProvider
{
    public function register(): void
    {
        $this->app->singleton(Cache::class, RedisCache::class);
    }

    public function boot(): void
    {
        // Runs after all providers registered
        View::share('appName', config('app.name'));
    }
}

Core providers (like RouteServiceProvider, EventServiceProvider) are listed in config/app.php.


3. What are facades?

Facades provide a static interface to classes in the service container.

// Behind the scenes, Cache:: resolves CacheManager from the container
Cache::put('key', 'value', 3600);

// Equivalent without facade
app('cache')->put('key', 'value', 3600);
Facade Underlying class
Cache Illuminate\Cache\CacheManager
DB Illuminate\Database\DatabaseManager
Route Illuminate\Routing\Router
Auth Illuminate\Auth\AuthManager
Event Illuminate\Events\Dispatcher
Queue Illuminate\Queue\QueueManager

In tests, facades can be faked: Cache::fake().


4. What is the difference between @inject and constructor injection?

Method Where used Notes
Constructor injection Controllers, services, jobs Preferred — explicit
Method injection Controller actions Auto-resolved by the router
@inject directive Blade templates Injects a service into a view
app() / resolve() Anywhere Manual — use sparingly
// Method injection — router resolves PaymentService
public function store(Request $request, PaymentService $svc): JsonResponse
{
    $svc->charge($request->all());
}

// Blade @inject
@inject('stats', 'App\Services\StatsService')
<p>Users: {{ $stats->totalUsers() }}</p>

5. What is the difference between config() and env()?

  • env() reads from the .env file directly. Should only be called inside config files — never in controllers or views.
  • config() reads the compiled config cache, which is fast.
// Wrong — breaks when config is cached
$key = env('STRIPE_SECRET');

// Correct — reads from config/services.php
$key = config('services.stripe.secret');

Run php artisan config:cache in production to cache all config files into a single file.


Routing

6. What are route model bindings?

Laravel automatically resolves an Eloquent model by its primary key (or a custom column) from the route segment.

// Implicit binding — {user} → App\Models\User::findOrFail($id)
Route::get('/users/{user}', [UserController::class, 'show']);

// Custom key — resolve by slug
Route::get('/posts/{post:slug}', [PostController::class, 'show']);

// Explicit binding in RouteServiceProvider
Route::bind('user', fn ($value) => User::where('uuid', $value)->firstOrFail());

Returns 404 automatically if the model is not found.


7. How do route groups work?

Route groups share attributes (middleware, prefix, name prefix, namespace) across many routes.

Route::prefix('api/v1')
    ->middleware(['auth:sanctum', 'throttle:60,1'])
    ->name('api.')
    ->group(function () {
        Route::get('/users', [UserController::class, 'index'])->name('users.index');
        Route::post('/users', [UserController::class, 'store'])->name('users.store');
    });

8. What is the difference between Route::resource and Route::apiResource?

Route::resource generates 7 routes (index, create, store, show, edit, update, destroy).
Route::apiResource generates 5 routes — omits create and edit (no HTML form views needed for APIs).

Route::resource('photos', PhotoController::class);
Route::apiResource('photos', PhotoController::class);

// Limit to specific actions
Route::resource('photos', PhotoController::class)->only(['index', 'show']);
Route::resource('photos', PhotoController::class)->except(['destroy']);

9. How do you create and apply middleware?

php artisan make:middleware EnsureEmailIsVerified
class EnsureEmailIsVerified
{
    public function handle(Request $request, Closure $next): Response
    {
        if (! $request->user()->hasVerifiedEmail()) {
            return response()->json(['message' => 'Email not verified.'], 403);
        }
        return $next($request);
    }
}

Register and apply:

// Register in bootstrap/app.php (Laravel 11) or Http/Kernel.php (Laravel 10)
->withMiddleware(function (Middleware $middleware) {
    $middleware->alias(['verified.email' => EnsureEmailIsVerified::class]);
})

// Apply to route
Route::get('/dashboard', DashboardController::class)->middleware('verified.email');

10. What are named routes and how do you redirect to them?

Route::get('/users/{id}/profile', [UserController::class, 'profile'])->name('users.profile');

// Generate URL
$url = route('users.profile', ['id' => 42]);

// Redirect
return redirect()->route('users.profile', ['id' => 42]);

// Check current route in Blade
@if (request()->routeIs('users.profile'))
    <li class="active">Profile</li>
@endif

Eloquent ORM

11. What are the Eloquent relationship types?

Relationship Method Example
One-to-one hasOne / belongsTo User → Phone
One-to-many hasMany / belongsTo Post → Comments
Many-to-many belongsToMany User ↔ Role
Has-one-through hasOneThrough Country → Capital (through Continent)
Has-many-through hasManyThrough Country → Posts (through User)
Polymorphic one morphOne / morphTo Comment → Image or Video
Polymorphic many morphMany / morphTo Post or Video → Comments
Many-to-many poly morphToMany / morphedByMany Post/Video → Tags
// Many-to-many with pivot table
class User extends Model
{
    public function roles(): BelongsToMany
    {
        return $this->belongsToMany(Role::class)
            ->withPivot('assigned_at')
            ->withTimestamps();
    }
}

$user->roles()->attach($roleId, ['assigned_at' => now()]);
$user->roles()->sync([1, 2, 3]);
$user->roles()->detach($roleId);

12. What is eager loading and why does it matter?

Eager loading prevents the N+1 query problem by loading relationships in a single additional query.

// N+1 problem — executes 1 + N queries
$posts = Post::all();
foreach ($posts as $post) {
    echo $post->author->name; // fires a query per post
}

// Eager loading — executes 2 queries total
$posts = Post::with('author')->get();

// Multiple relationships
$posts = Post::with(['author', 'comments.author', 'tags'])->get();

// Constrained eager loading
$posts = Post::with(['comments' => function ($query) {
    $query->where('approved', true)->orderBy('created_at', 'desc');
}])->get();

Use withCount() to load counts without hydrating models:

$posts = Post::withCount('comments')->get();
echo $post->comments_count;

13. What are local and global query scopes?

Local scopes are reusable query constraints you call explicitly.
Global scopes are automatically applied to all queries on a model.

class Post extends Model
{
    // Local scope — called as Post::published()->get()
    public function scopePublished(Builder $query): void
    {
        $query->where('status', 'published');
    }

    // Local scope with parameter
    public function scopeOfType(Builder $query, string $type): void
    {
        $query->where('type', $type);
    }
}

// Usage
$posts = Post::published()->ofType('news')->latest()->get();
// Global scope — always applied
class ActiveScope implements Scope
{
    public function apply(Builder $builder, Model $model): void
    {
        $builder->where('active', true);
    }
}

class User extends Model
{
    protected static function booted(): void
    {
        static::addGlobalScope(new ActiveScope());
    }
}

// Remove global scope for a query
User::withoutGlobalScope(ActiveScope::class)->get();

14. What are Eloquent accessors and mutators?

Accessors transform attribute values when you access them.
Mutators transform values when you set them.

// Laravel 9+ unified accessor/mutator
class User extends Model
{
    protected function name(): Attribute
    {
        return Attribute::make(
            get: fn ($value) => ucfirst($value),
            set: fn ($value) => strtolower($value),
        );
    }

    // Computed (virtual) attribute — not stored
    protected function fullName(): Attribute
    {
        return Attribute::make(
            get: fn () => "{$this->first_name} {$this->last_name}",
        );
    }
}

$user->name = 'JOHN'; // stored as 'john'
echo $user->name;     // outputs 'John'
echo $user->full_name; // 'John Doe'

15. What is the difference between save(), create(), and fill()?

Method Mass assignment guard Persists?
create($data) Checks $fillable/$guarded Yes
fill($data) Checks $fillable/$guarded No — call save() after
forceFill($data) Bypasses guard No
save() N/A — saves current state Yes
update($data) Checks $fillable/$guarded Yes
// create() — mass assign + persist
$user = User::create(['name' => 'Alice', 'email' => 'alice@example.com']);

// fill() + save()
$user = new User();
$user->fill(['name' => 'Alice', 'email' => 'alice@example.com']);
$user->save();

// update existing
$user->update(['name' => 'Bob']);

// First-or-create patterns
$user = User::firstOrCreate(['email' => 'alice@example.com'], ['name' => 'Alice']);
$user = User::updateOrCreate(['email' => 'alice@example.com'], ['name' => 'Alice']);

16. What is soft deleting?

Soft delete sets a deleted_at timestamp instead of removing the record.

use Illuminate\Database\Eloquent\SoftDeletes;

class Post extends Model
{
    use SoftDeletes;
}

$post->delete();          // sets deleted_at, record stays in DB
Post::all();              // excludes soft-deleted records
Post::withTrashed()->get(); // includes soft-deleted
Post::onlyTrashed()->get(); // only soft-deleted
$post->restore();         // clears deleted_at
$post->forceDelete();     // truly removes the record

Migration:

$table->softDeletes(); // adds nullable deleted_at timestamp

Blade Templating

17. What are Blade components?

Components are reusable, encapsulated UI pieces — similar to React components.

php artisan make:component Alert
// app/View/Components/Alert.php
class Alert extends Component
{
    public function __construct(public string $type = 'info') {}

    public function render(): View
    {
        return view('components.alert');
    }
}
<!-- resources/views/components/alert.blade.php -->
<div class="alert alert-{{ $type }}">
    {{ $slot }}
</div>

<!-- Named slots -->
<div class="card">
    <div class="card-header">{{ $header }}</div>
    <div class="card-body">{{ $slot }}</div>
</div>
<!-- Usage -->
<x-alert type="danger">Something went wrong!</x-alert>

<x-card>
    <x-slot:header>User Profile</x-slot:header>
    <p>Profile content here.</p>
</x-card>

18. What are the key Blade directives?

Directive Purpose
@if / @elseif / @else / @endif Conditionals
@unless Inverted @if
@isset / @empty Null/empty checks
@foreach / @endforeach Loops
@forelse / @empty / @endforelse Loop with empty state
@for / @while C-style loops
@auth / @guest Auth state
@can / @cannot Authorization
@include / @includeIf Include sub-views
@extends / @section / @yield Template inheritance
@csrf CSRF token field
@method('PUT') HTML form method spoofing
@stack / @push Stackable content sections

Authentication & Authorization

19. What is the difference between Laravel Breeze, Jetstream, and Sanctum?

Package Purpose Auth type Frontend
Breeze Simple auth scaffold Session Blade, Livewire, React, Vue
Jetstream Full auth + teams Session Livewire or Inertia
Sanctum API token auth Token / Session SPA or mobile
Passport Full OAuth2 server OAuth2 Any

Use Sanctum for your own SPA or mobile app talking to your Laravel API.
Use Passport when you need to issue OAuth2 tokens to third-party clients.


20. How do gates and policies differ?

Gates are closures for simple, model-agnostic authorization.
Policies are classes that organize authorization around a model.

// Gate — defined in AuthServiceProvider
Gate::define('view-admin', fn (User $user) => $user->isAdmin());

// Check
if (Gate::allows('view-admin')) { ... }
abort_if(Gate::denies('view-admin'), 403);
// Policy
class PostPolicy
{
    public function update(User $user, Post $post): bool
    {
        return $user->id === $post->user_id;
    }
}

// In controller
$this->authorize('update', $post);

// In Blade
@can('update', $post)
    <a href="{{ route('posts.edit', $post) }}">Edit</a>
@endcan

21. How does Laravel Sanctum work for SPA authentication?

Sanctum issues CSRF-cookie-based session auth for same-domain SPAs and token-based auth for mobile/third-party clients.

// SPA — CSRF cookie (no tokens)
// 1. GET /sanctum/csrf-cookie to set XSRF-TOKEN cookie
// 2. Login via POST /login — sets session cookie
// 3. All subsequent requests use cookies automatically

// Token-based (mobile/API clients)
$token = $user->createToken('mobile')->plainTextToken;
// Client sends: Authorization: Bearer {token}

// Scopes
$token = $user->createToken('mobile', ['read:posts', 'write:posts'])->plainTextToken;

$user->tokens()->where('id', $id)->delete(); // revoke specific token
$user->tokens()->delete();                   // revoke all

API Development

22. What are API Resources?

API Resources transform Eloquent models into JSON — a presentation layer between your models and API responses.

// php artisan make:resource UserResource
class UserResource extends JsonResource
{
    public function toArray(Request $request): array
    {
        return [
            'id'         => $this->id,
            'name'       => $this->name,
            'email'      => $this->email,
            'role'       => $this->whenLoaded('role', fn () => $this->role->name),
            'created_at' => $this->created_at->toISOString(),
            'links'      => [
                'self' => route('users.show', $this->id),
            ],
        ];
    }
}

// Usage
return new UserResource($user);
return UserResource::collection(User::paginate(20));
// Resource collection with meta
class UserCollection extends ResourceCollection
{
    public function toArray(Request $request): array
    {
        return [
            'data' => $this->collection,
            'meta' => ['total_active' => User::where('active', true)->count()],
        ];
    }
}

23. How do you implement rate limiting?

// config/routes — named rate limiter
RateLimiter::for('api', function (Request $request) {
    return $request->user()
        ? Limit::perMinute(60)->by($request->user()->id)
        : Limit::perMinute(10)->by($request->ip());
});

// Apply to route group
Route::middleware(['auth:sanctum', 'throttle:api'])->group(...);

// Custom per-route limit
Route::post('/login', LoginController::class)
    ->middleware('throttle:5,1');  // 5 per minute

// Multiple limits
RateLimiter::for('uploads', function (Request $request) {
    return [
        Limit::perMinute(3),
        Limit::perDay(100)->by($request->user()->id),
    ];
});

24. How do you version a Laravel API?

URL versioning (most common):

Route::prefix('v1')->name('v1.')->group(base_path('routes/v1.php'));
Route::prefix('v2')->name('v2.')->group(base_path('routes/v2.php'));

Header versioning:

Route::middleware('api.version:v2')->group(function () { ... });

Structure approach:

app/Http/Controllers/
    Api/
        V1/UserController.php
        V2/UserController.php

Queues & Jobs

25. How do you create and dispatch a job?

php artisan make:job SendWelcomeEmail
class SendWelcomeEmail implements ShouldQueue
{
    use Queueable;

    public function __construct(private readonly User $user) {}

    public function handle(Mailer $mailer): void
    {
        $mailer->to($this->user->email)->send(new WelcomeMail($this->user));
    }

    public function failed(Throwable $exception): void
    {
        // Notify developer or mark user
    }
}

// Dispatch
SendWelcomeEmail::dispatch($user);
SendWelcomeEmail::dispatch($user)->onQueue('emails');
SendWelcomeEmail::dispatch($user)->delay(now()->addMinutes(5));

// Dispatch synchronously (bypasses queue)
SendWelcomeEmail::dispatchSync($user);

26. What are queue workers and how do you configure retries?

# Start worker
php artisan queue:work redis --queue=emails,default --tries=3 --timeout=60

# Process one job and stop
php artisan queue:work --once

# Fresh worker (good for development)
php artisan queue:listen
class SendWelcomeEmail implements ShouldQueue
{
    public int $tries = 3;
    public int $timeout = 30;
    public int $backoff = 60; // seconds before retry

    // Exponential backoff
    public function backoff(): array
    {
        return [1, 5, 10]; // seconds between retries
    }

    // Only retry if exception is retriable
    public function retryUntil(): DateTime
    {
        return now()->addHours(2);
    }
}

27. What is Laravel Horizon?

Horizon is a dashboard and configuration manager for Redis queues.

// config/horizon.php — per-environment worker pools
'environments' => [
    'production' => [
        'supervisor-1' => [
            'connection' => 'redis',
            'queue'      => ['default', 'emails', 'notifications'],
            'balance'    => 'auto',
            'processes'  => 10,
            'tries'      => 3,
        ],
    ],
],
php artisan horizon          # start Horizon
php artisan horizon:pause    # pause all workers
php artisan horizon:continue
php artisan horizon:terminate # graceful shutdown

Dashboard at /horizon shows throughput, wait times, failed jobs, and metrics per queue.


Events & Listeners

28. How do events and listeners work in Laravel?

// Define event
class OrderShipped
{
    public function __construct(public readonly Order $order) {}
}

// Define listener
class SendShipmentNotification implements ShouldQueue
{
    public function handle(OrderShipped $event): void
    {
        Mail::to($event->order->user)->send(new ShipmentMail($event->order));
    }
}

// Register in EventServiceProvider (or autodiscovery)
protected $listen = [
    OrderShipped::class => [
        SendShipmentNotification::class,
        UpdateInventory::class,
    ],
];

// Fire event
event(new OrderShipped($order));
OrderShipped::dispatch($order); // alternative

29. What is event broadcasting?

Broadcasting pushes server-side events to the browser via WebSockets (Laravel Reverb, Pusher, Ably).

class OrderStatusUpdated implements ShouldBroadcast
{
    public function __construct(public readonly Order $order) {}

    public function broadcastOn(): Channel
    {
        return new PrivateChannel('orders.' . $this->order->id);
    }

    public function broadcastWith(): array
    {
        return ['status' => $this->order->status];
    }
}

// Laravel 11 — start Reverb server
php artisan reverb:start

// Frontend (Laravel Echo + Pusher.js)
Echo.private(`orders.${orderId}`)
    .listen('OrderStatusUpdated', (e) => {
        console.log(e.status);
    });

Testing

30. How do you test a Laravel API endpoint?

use Illuminate\Foundation\Testing\RefreshDatabase;

class UserControllerTest extends TestCase
{
    use RefreshDatabase;

    public function test_authenticated_user_can_view_profile(): void
    {
        $user = User::factory()->create();

        $response = $this->actingAs($user, 'sanctum')
            ->getJson('/api/users/' . $user->id);

        $response->assertOk()
            ->assertJsonStructure(['data' => ['id', 'name', 'email']])
            ->assertJsonPath('data.email', $user->email);
    }

    public function test_unauthenticated_request_returns_401(): void
    {
        $this->getJson('/api/users/1')->assertUnauthorized();
    }
}

31. What are model factories?

Factories generate fake Eloquent model instances for testing.

class UserFactory extends Factory
{
    public function definition(): array
    {
        return [
            'name'              => fake()->name(),
            'email'             => fake()->unique()->safeEmail(),
            'password'          => Hash::make('password'),
            'email_verified_at' => now(),
        ];
    }

    // State modifier
    public function admin(): static
    {
        return $this->state(fn () => ['role' => 'admin']);
    }

    public function unverified(): static
    {
        return $this->state(fn () => ['email_verified_at' => null]);
    }
}

// Usage
$user = User::factory()->create();
$admin = User::factory()->admin()->create();
$users = User::factory()->count(10)->create();

// With relationship
$post = Post::factory()->for(User::factory())->create();
$posts = Post::factory()->count(3)->has(Comment::factory()->count(5))->create();

32. What is the difference between RefreshDatabase and DatabaseTransactions?

Trait Mechanism Speed Notes
RefreshDatabase Runs migrations fresh before suite Slow (first run), fast (cached) Full isolation
DatabaseTransactions Wraps each test in a transaction, rolls back Fast Doesn't work with multiple DB connections or queue workers
No trait No cleanup Use for read-only tests
// Fastest setup for most test suites
class ExampleTest extends TestCase
{
    use RefreshDatabase; // migrations + seeders if needed

    public function test_example(): void { ... }
}

33. How do you mock external services in Laravel tests?

// Mock a service class
public function test_sends_email_on_registration(): void
{
    Mail::fake();

    $this->postJson('/api/register', [
        'name'     => 'Alice',
        'email'    => 'alice@example.com',
        'password' => 'secret123',
    ])->assertCreated();

    Mail::assertSent(WelcomeMail::class, fn ($mail) =>
        $mail->hasTo('alice@example.com')
    );
}

// Queue fake
Queue::fake();
dispatch(new ProcessOrder($order));
Queue::assertPushed(ProcessOrder::class);

// HTTP client fake
Http::fake([
    'stripe.com/*' => Http::response(['id' => 'ch_123'], 200),
    'sms.api.com/*' => Http::sequence()->push(['status' => 'sent']),
]);

Performance & Caching

34. How do you cache in Laravel?

// Store for 1 hour
Cache::put('users.count', User::count(), 3600);

// Retrieve with default
$count = Cache::get('users.count', 0);

// Remember pattern — most common
$users = Cache::remember('all.users', 3600, fn () => User::all());

// Forever
Cache::forever('settings', Settings::all());

// Remove
Cache::forget('users.count');
Cache::flush();

// Tags (Redis/Memcached only)
Cache::tags(['users', 'admins'])->remember('admin-list', 3600, fn () =>
    User::where('role', 'admin')->get()
);
Cache::tags(['users'])->flush(); // invalidate all user caches

Drivers: file (default), redis, memcached, dynamodb, database, array (test).


35. How do you prevent N+1 queries?

// Detect in dev — add to AppServiceProvider::boot()
Model::preventLazyLoading(! app()->isProduction());

// Fix: eager load relationships
$posts = Post::with(['author', 'comments.author'])->get();

// Load after retrieval
$posts->load('comments');
$posts->loadCount('comments');
$posts->loadMissing('author'); // only if not already loaded

// Subquery selects for aggregates
$users = User::addSelect([
    'latest_post_title' => Post::select('title')
        ->whereColumn('user_id', 'users.id')
        ->latest()
        ->limit(1),
])->get();

Security

36. How does Laravel prevent SQL injection?

Laravel uses PDO parameter binding for all query builder and Eloquent calls.

// Safe — parameter bound
User::where('email', $request->email)->first();
DB::table('users')->where('email', '=', $request->email)->first();

// Raw expression — SAFE — value is still bound
User::whereRaw('email = ?', [$request->email])->first();

// Dangerous — never concatenate user input
DB::statement("SELECT * FROM users WHERE email = '" . $email . "'"); // NEVER DO THIS

37. How does Laravel protect against CSRF?

Laravel generates a CSRF token per session and validates it on POST, PUT, PATCH, DELETE requests.

<!-- Include token in forms -->
<form method="POST">
    @csrf
    ...
</form>
// Exclude certain routes in VerifyCsrfToken middleware
protected $except = [
    'stripe/*',
    'api/*', // APIs typically use token auth instead
];

For SPAs: Sanctum's /sanctum/csrf-cookie endpoint sets the XSRF-TOKEN cookie, which Axios/fetch sends back as the X-XSRF-TOKEN header.


38. What is mass assignment and how is it prevented?

Mass assignment allows setting model attributes via an array. Guarded against untrusted user input via $fillable and $guarded.

class User extends Model
{
    // Allowlist — recommended
    protected $fillable = ['name', 'email', 'password'];

    // OR blocklist (less safe if you add columns later)
    protected $guarded = ['role', 'is_admin'];
}

// If user sends ['role' => 'admin'] in request, it's ignored
User::create($request->all()); // safe — only fillable attributes used
User::create($request->only(['name', 'email', 'password'])); // even safer

Advanced Topics

39. What is Laravel's task scheduling?

// app/Console/Kernel.php (Laravel 10) or routes/console.php (Laravel 11)
Schedule::job(new GenerateDailyReport)->dailyAt('01:00');
Schedule::command('emails:prune')->weekly()->mondays()->at('08:00');
Schedule::call(fn () => Setting::set('last_ping', now()))->everyFiveMinutes();
Schedule::exec('backup.sh')->daily()->runInBackground()->sendOutputTo('/var/log/backup.log');

// Prevent overlapping tasks
Schedule::job(new LongRunningJob)->everyMinute()->withoutOverlapping();

// Run in production only
Schedule::job(new SyncJob)->hourly()->environments('production');
# Add to server's crontab — runs every minute
* * * * * cd /var/www/html && php artisan schedule:run >> /dev/null 2>&1

40. What are observers?

Observers group multiple model event listeners into a single class.

// php artisan make:observer UserObserver --model=User
class UserObserver
{
    public function created(User $user): void
    {
        SendWelcomeEmail::dispatch($user);
    }

    public function updated(User $user): void
    {
        if ($user->isDirty('email')) {
            $user->sendEmailVerificationNotification();
        }
    }

    public function deleted(User $user): void
    {
        $user->posts()->delete();
    }
}

// Register in AppServiceProvider::boot()
User::observe(UserObserver::class);

Model events: creating, created, updating, updated, saving, saved, deleting, deleted, restoring, restored.


41. What is Laravel Octane?

Octane boots your application once and keeps it in memory using Swoole or RoadRunner, eliminating bootstrap overhead per request.

php artisan octane:install --server=swoole
php artisan octane:start --workers=8 --task-workers=4

Performance gains: 5-10× more requests/second compared to php-fpm.

Gotchas — avoid state leaking between requests:

// Bad — static state persists across requests in Octane
class OrderService
{
    public static array $cache = [];
}

// Good — use the DI container
$this->app->scoped(OrderService::class); // fresh per request

42. How do you use database transactions?

// Automatic rollback on exception
DB::transaction(function () {
    $order  = Order::create([...]);
    Payment::create(['order_id' => $order->id, ...]);
    $order->sendConfirmationEmail();
});

// Manual control
DB::beginTransaction();
try {
    // ...
    DB::commit();
} catch (Throwable $e) {
    DB::rollBack();
    throw $e;
}

// Retry on deadlock
DB::transaction(function () { ... }, attempts: 5);

43. What is a repository pattern in Laravel?

The repository pattern decouples data access from business logic, making code testable and swappable.

// Interface
interface UserRepositoryInterface
{
    public function findByEmail(string $email): ?User;
    public function paginate(int $perPage): LengthAwarePaginator;
}

// Eloquent implementation
class EloquentUserRepository implements UserRepositoryInterface
{
    public function findByEmail(string $email): ?User
    {
        return User::where('email', $email)->first();
    }

    public function paginate(int $perPage): LengthAwarePaginator
    {
        return User::latest()->paginate($perPage);
    }
}

// Bind in service provider
$this->app->bind(UserRepositoryInterface::class, EloquentUserRepository::class);

// In test — swap with a mock
$this->app->bind(UserRepositoryInterface::class, InMemoryUserRepository::class);

44. What are pipelines?

Laravel's Pipeline sends an object through a series of stages (pipes) — great for multi-step processing.

$result = Pipeline::send($order)
    ->through([
        ValidateInventory::class,
        ApplyDiscount::class,
        ChargePayment::class,
        SendConfirmation::class,
    ])
    ->thenReturn();

// Pipe implementation
class ApplyDiscount
{
    public function handle(Order $order, Closure $next): Order
    {
        if ($order->user->isPremium()) {
            $order->applyDiscount(0.1);
        }
        return $next($order);
    }
}

45. What is Laravel Livewire?

Livewire is a full-stack component framework that lets you write reactive UIs in PHP without JavaScript.

class Counter extends Component
{
    public int $count = 0;

    public function increment(): void
    {
        $this->count++;
    }

    public function render(): View
    {
        return view('livewire.counter');
    }
}
<!-- resources/views/livewire/counter.blade.php -->
<div>
    <button wire:click="increment">+</button>
    <span>{{ $count }}</span>
</div>

Livewire sends AJAX requests on user interaction and surgically updates the DOM — no page reload.


46. What is the difference between has() and whereHas()?

// has() — filter models that have a relationship (any)
$usersWithPosts = User::has('posts')->get();
$usersWithManyPosts = User::has('posts', '>=', 5)->get();

// whereHas() — filter based on relationship constraints
$usersWithPublishedPosts = User::whereHas('posts', function ($query) {
    $query->where('status', 'published');
})->get();

// doesntHave / whereDoesntHave
$usersWithNoPosts = User::doesntHave('posts')->get();

47. What is dependency injection in controllers?

Laravel automatically injects dependencies into controller constructors and action methods.

class PostController extends Controller
{
    // Constructor injection — persists for all actions
    public function __construct(private readonly PostRepository $repo) {}

    // Method injection — resolved fresh per action
    public function store(StorePostRequest $request, ImageService $images): JsonResponse
    {
        $data            = $request->validated();
        $data['image']   = $images->upload($request->file('image'));
        $post            = $this->repo->create($data);

        return response()->json(new PostResource($post), 201);
    }
}

48. What are Form Requests?

Form Requests extract validation and authorization logic out of controllers.

// php artisan make:request StorePostRequest
class StorePostRequest extends FormRequest
{
    public function authorize(): bool
    {
        return $this->user()->can('create', Post::class);
    }

    public function rules(): array
    {
        return [
            'title'    => ['required', 'string', 'max:255'],
            'body'     => ['required', 'string', 'min:10'],
            'category' => ['required', 'exists:categories,id'],
            'tags'     => ['array'],
            'tags.*'   => ['exists:tags,id'],
        ];
    }

    public function messages(): array
    {
        return [
            'category.exists' => 'Please select a valid category.',
        ];
    }
}

// Controller — $request is already validated
public function store(StorePostRequest $request): JsonResponse
{
    $post = Post::create($request->validated());
    return response()->json(new PostResource($post), 201);
}

49. How do you handle file uploads?

// Store uploaded file
$path = $request->file('avatar')->store('avatars', 's3');

// With custom filename
$path = $request->file('avatar')
    ->storeAs('avatars', $user->id . '.jpg', 's3');

// Validation
$request->validate([
    'avatar' => ['required', 'image', 'mimes:jpg,png,webp', 'max:2048'],
    'docs'   => ['required', 'array', 'max:5'],
    'docs.*' => ['file', 'mimes:pdf', 'max:10240'],
]);

// Serving private files
return Storage::disk('s3')->response('avatars/' . $filename);
return Storage::temporaryUrl('avatars/' . $filename, now()->addMinutes(30)); // S3 signed URL

50. What are common Laravel anti-patterns?

Anti-pattern Problem Fix
Fat controllers Logic in controller, untestable Move to service/action classes
env() outside config Breaks config cache Use config() everywhere, env() only in config files
DB::select() for everything Bypasses Eloquent features Use query builder or Eloquent; raw SQL as last resort
User::all() Loads entire table Paginate: User::paginate(20)
No eager loading N+1 queries Use with(), enable preventLazyLoading() in dev
Synchronous heavy tasks Slow responses Dispatch to queue
No form requests Bloated controllers Extract to FormRequest classes
Testing with real HTTP Slow, fragile Use Http::fake(), Mail::fake(), Queue::fake()

Comparison

Laravel vs Django vs Rails vs Spring Boot

Feature Laravel Django Rails Spring Boot
Language PHP Python Ruby Java/Kotlin
Philosophy Expressive, developer joy Pragmatic, batteries-included Convention over config Enterprise-grade
ORM Eloquent (ActiveRecord) Django ORM Active Record JPA/Hibernate
Template engine Blade Django templates / Jinja2 ERB / Haml Thymeleaf
Auth Sanctum / Breeze / Fortify django-allauth / rest_framework Devise Spring Security
Queue Horizon + Redis Celery + Redis Sidekiq + Redis Spring Batch
Async/reactive Octane (Swoole) Async views (ASGI) async Action Controller WebFlux
Learning curve Low Medium Low High
Performance Medium Medium Medium High
Best for SaaS, APIs, full-stack PHP Data-heavy web apps Rapid prototyping Enterprise / microservices

Common mistakes

Mistake Why it's wrong Fix
env() in controllers Breaks when config is cached Use config('app.key')
User::all() in views Full table scan, no caching Paginate + cache
Lazy loading relationships N+1 queries with() or preventLazyLoading()
No queue for emails Request hangs for seconds SendEmail::dispatch($user)
Putting logic in Blade Hard to test Move to Presenters or View Models
Skipping $fillable Mass assignment vulnerability Always define $fillable
Not using transactions Partial writes on failure Wrap related writes in DB::transaction()
Committing .env Exposes secrets .env in .gitignore, use .env.example

FAQ

Q: What PHP version does Laravel 11 require?
A: PHP 8.2 or higher. Laravel 10 requires PHP 8.1+.

Q: When should I use Eloquent vs the query builder vs raw SQL?
A: Eloquent for CRUD and relationships; query builder for complex queries or performance-sensitive reports; raw SQL only for database-specific features unavailable in the builder.

Q: How is service container different from a singleton?
A: The container manages the full lifecycle — it can create a new instance per resolve (bind), create once and share (singleton), or create once per request (scoped). A PHP singleton is a design pattern; the container abstracts this at the framework level.

Q: What is the difference between dispatch() and dispatchSync()?
A: dispatch() pushes the job onto the queue driver. dispatchSync() runs the job immediately in the current process (useful for testing and local dev with QUEUE_CONNECTION=sync).

Q: How do I speed up Laravel in production?
A: php artisan config:cache, route:cache, view:cache, event:cache — cache everything. Use Redis for cache, session, and queue. Consider Octane with Swoole for high-throughput APIs.

Q: What is the difference between belongsTo and hasOne?
A: They're two sides of the same relationship. The model that holds the foreign key uses belongsTo; the model on the other side uses hasOne (or hasMany). Example: Post has user_id column → Post::belongsTo(User::class) and User::hasMany(Post::class).

Keep reading

All Toolmingotools are free & run in your browser

No sign-up, no upload, no watermark. Your files never leave your device.

Browse all tools