Top 60 Laravel Interview Questions (2026)

The 60 Laravel questions interviewers actually ask, with direct answers, runnable code, and what the interviewer is listening for. Grouped for freshers, intermediate, and experienced rounds.

60 questions with answers

What Is Laravel?

Key Takeaways

  • Laravel is an open-source PHP web framework that follows the MVC pattern and ships batteries-included: routing, ORM, migrations, queues, auth, and more.
  • Its signature pieces are Eloquent (the ActiveRecord ORM), Blade (templating), Artisan (the CLI), and the service container that wires everything together.
  • Interviews test how well you understand the request lifecycle, Eloquent relationships and the N+1 problem, and the container, not just syntax.
  • This page is a question bank: work your tier first, read one tier up, and say answers out loud because delivery is evaluated too.

Laravel is an open-source PHP web framework created by Taylor Otwell and first released in 2011, built around the model-view-controller pattern and known for expressive, readable syntax. It ships with almost everything a web app needs out of the box: a router, the Eloquent ORM, database migrations, a queue system, authentication scaffolding, the Blade templating engine, and the Artisan command-line tool. That completeness is why teams pick it: you spend time on features, not plumbing. In interviews, Laravel questions probe understanding of the request lifecycle, the service container and dependency injection, Eloquent relationships and the N+1 query problem, and middleware, rather than memorized method names. This page collects the 60 questions that come up most, each with a direct answer and runnable code. If you're building fundamentals, the official Laravel documentation is the canonical reference; increasingly the first backend round is a live AI coding interview, so pair this bank with our AI interview preparation guides for the format side.

60Questions with answers on this page
3Difficulty tiers: freshers, intermediate, experienced
24Runnable code snippets you can practice from
45-60 minTypical length of a Laravel technical round

Watch: Laravel PHP Framework Tutorial - Full Course for Beginners (2019)

Video: Laravel PHP Framework Tutorial - Full Course for Beginners (2019) (freeCodeCamp.org, YouTube)

Test yourself and earn a certificate

10 quick questions. Score 70%+ to download your Laravel certificate.

Jump to quiz

All Questions on This Page

60 questions
Laravel Interview Questions for Freshers
  1. 1. What is Laravel and why do teams choose it?
  2. 2. How does the MVC pattern work in Laravel?
  3. 3. Walk through the Laravel request lifecycle.
  4. 4. What is Artisan and what do you use it for?
  5. 5. How do you define routes in Laravel?
  6. 6. What is route model binding?
  7. 7. What is Eloquent and how does a model map to a table?
  8. 8. What is the difference between Eloquent and the query builder?
  9. 9. What are migrations and why use them?
  10. 10. What is Blade and what makes it useful?
  11. 11. What is middleware and give an example?
  12. 12. How does configuration and the .env file work in Laravel?
  13. 13. What are facades in Laravel?
  14. 14. What are Eloquent relationships and name the common types?
  15. 15. How do you validate incoming request data?
  16. 16. What is Tinker and when do you use it?
  17. 17. What are Laravel Collections?
  18. 18. What are seeders and factories?
  19. 19. How does Laravel protect against CSRF attacks?
  20. 20. How do you access request input in a controller?
  21. 21. What are named routes and why use them?
  22. 22. How do sessions and flash messages work in Laravel?
  23. 23. What role does Composer play in a Laravel project?
  24. 24. How do you debug and log in Laravel?
Laravel Intermediate Interview Questions
  1. 25. What is the N+1 query problem and how do you fix it?
  2. 26. What is the difference between eager and lazy loading?
  3. 27. What is the service container and how does dependency injection work?
  4. 28. What are service providers and what goes in register vs boot?
  5. 29. How do queues and jobs work in Laravel?
  6. 30. How do events and listeners work, and when should you use them?
  7. 31. What are Form Request classes and why use them?
  8. 32. What are API Resources and what problem do they solve?
  9. 33. What are Laravel's authentication options and when do you use each?
  10. 34. What is the difference between gates and policies?
  11. 35. What are query scopes in Eloquent?
  12. 36. What are accessors, mutators, and attribute casts?
  13. 37. How do many-to-many relationships and pivot tables work?
  14. 38. What are soft deletes and how do they work?
  15. 39. How do you use database transactions in Laravel?
  16. 40. How does caching work in Laravel?
  17. 41. How do you test a Laravel application?
  18. 42. How does task scheduling work in Laravel?
  19. 43. Why use Collections over plain PHP arrays?
  20. 44. What do config:cache and route:cache do, and when do you use them?
Laravel Interview Questions for Experienced Developers
  1. 45. How does the service container resolve and build a dependency?
  2. 46. When do you choose middleware, events, or a service class for logic?
  3. 47. Should you use the repository pattern with Eloquent?
  4. 48. How do you process millions of rows without exhausting memory?
  5. 49. How do you make queued jobs reliable in production?
  6. 50. What is Laravel Horizon and when do you reach for it?
  7. 51. Beyond N+1, how do you optimize Eloquent-heavy code?
  8. 52. What are polymorphic relationships and when are they the right tool?
  9. 53. How do you write a custom attribute cast, and why?
  10. 54. What are macros in Laravel and when would you use one?
  11. 55. How would you design multi-tenancy in a Laravel application?
  12. 56. How do you version and structure a large Laravel API?
  13. 57. How do you detect N+1 and other query problems before production?
  14. 58. What are model events and observers, and what's the risk?
  15. 59. A Laravel endpoint is slow in production. Walk through your debugging approach.
  16. 60. Design question: how would you build a URL shortener in Laravel?

Laravel Interview Questions for Freshers

Freshers24 questions

The fundamentals every entry-level round checks. If any answer here surprises you, that's your study list.

Q1. What is Laravel and why do teams choose it?

Laravel is an open-source PHP web framework built on the MVC pattern, known for expressive syntax and a batteries-included toolset. It ships routing, the Eloquent ORM, migrations, queues, auth scaffolding, the Blade templating engine, and the Artisan CLI out of the box.

Teams choose it because that completeness cuts setup to near zero: you build features instead of assembling plumbing. Convention over configuration means new developers find their way quickly, and the first-party ecosystem (Forge, Vapor, Sanctum, Horizon) covers deployment, auth, and queues.

Key point: A one-line definition plus two concrete built-in examples beats a memorized feature list. Interviewers open with this to hear how you organize an answer.

Watch a deeper explanation

Video: Laravel Crash Course (Traversy Media, YouTube)

Q2. How does the MVC pattern work in Laravel?

Models represent data and business rules (usually Eloquent classes mapped to tables), views handle presentation (Blade templates), and controllers coordinate: they receive the request, call models, and return a view or response.

The router sits in front, mapping a URL to a controller method. Keeping logic in models and services rather than controllers is the habit interviewers look for, because fat controllers are the classic maintainability trap.

How an MVC request moves through Laravel

1Route matches
The router maps the incoming URL and verb to a controller method.
2Controller coordinates
The controller validates input and calls models or service classes for the work.
3Model touches data
Eloquent models read and write the database and return domain objects.
4View renders
The controller passes data to a Blade view, which returns the HTML response.

Keep business logic in models or service classes, not controllers. Fat controllers are the maintainability trap interviewers probe for.

Key point: The where business logic belongs (models or dedicated service classes, not controllers). That distinction signals you've maintained real Laravel code.

Q3. Walk through the Laravel request lifecycle.

Every request enters through public/index.php, which loads the autoloader and bootstraps the application from bootstrap/app.php. The HTTP kernel runs, global middleware execute, and the request is dispatched to the router.

The router matches a route, runs its route-specific middleware, resolves the controller (or closure) through the service container, and the controller returns a response. The response travels back out through middleware and is sent to the browser. Understanding this order explains where middleware, service providers, and the container each fit.

Key point: middleware run on the way in AND out.

Watch a deeper explanation

Video: What You Need to Know Before Learning Laravel | Learn Laravel The Right Way (Program With Gio, YouTube)

Q4. What is Artisan and what do you use it for?

Artisan is Laravel's command-line tool. You use it to scaffold code (make:model, make:controller, make:migration), run migrations, clear caches, run the queue worker, start a dev server, and run custom commands you write yourself.

It saves boilerplate and standardizes the project structure. You can list every command with php artisan list, and write your own commands by extending the Command class.

bash
php artisan make:model Post -mcr   # model + migration + controller + resource
php artisan migrate                # run pending migrations
php artisan route:list             # inspect all registered routes
php artisan queue:work             # process queued jobs

Key point: The -mcr flag combo (model, migration, controller, resource in one command) is a small detail that indicates day-to-day fluency.

Q5. How do you define routes in Laravel?

Routes live in the routes directory: web.php for stateful web routes (sessions, CSRF) and api.php for stateless API routes. You register them with the Route facade, one method per HTTP verb.

Routes can point to a closure or a controller method, accept parameters, and be named for URL generation. Grouping lets you share middleware, prefixes, or namespaces across many routes.

php
use App\Http\Controllers\PostController;

Route::get('/posts', [PostController::class, 'index'])->name('posts.index');
Route::get('/posts/{post}', [PostController::class, 'show']);
Route::post('/posts', [PostController::class, 'store'])->middleware('auth');

Q6. What is route model binding?

Route model binding automatically injects a model instance into your controller based on a route parameter. If a route has {post}, Laravel resolves the Post model whose ID matches and passes it in, throwing a 404 if none exists.

Implicit binding matches by primary key by default; you can bind by another column with getRouteKeyName() or in the route definition. It removes repetitive findOrFail() calls.

php
// route: Route::get('/posts/{post}', ...);
public function show(Post $post)
{
    // $post is already resolved from the {post} id, or 404 if missing
    return view('posts.show', compact('post'));
}

Key point: Volunteering the 404-on-miss behavior and binding-by-slug variant shows you've used it beyond the happy path.

Watch a deeper explanation

Video: Laravel PHP Framework Tutorial - Full Course for Beginners (2019) (freeCodeCamp.org, YouTube)

Q7. What is Eloquent and how does a model map to a table?

Eloquent is Laravel's ActiveRecord ORM. Each model class maps to a database table, and each instance maps to a row. By convention a Post model maps to a posts table, so you rarely configure the mapping explicitly.

Eloquent gives you expressive methods for CRUD, relationships, scopes, and events without writing SQL. You can still drop to the query builder or raw SQL when you need to.

php
class Post extends Model
{
    // maps to 'posts' table by convention
}

$post = Post::create(['title' => 'Hello', 'body' => 'World']);
$latest = Post::where('published', true)->latest()->first();
$post->update(['title' => 'Updated']);

Q8. What is the difference between Eloquent and the query builder?

The query builder is a fluent interface over raw SQL: DB::table('posts')->where(...)->get() returns plain rows (stdClass or arrays). Eloquent sits on top and returns model objects with relationships, casts, accessors, and events.

Reach for Eloquent when you want the object model and its conveniences, which is most application code. Drop to the query builder for bulk operations, complex reporting joins, or hot paths where hydrating full models is wasteful.

EloquentQuery builder
ReturnsModel objectsPlain rows (stdClass/array)
RelationshipsYesManual joins
Events, casts, scopesYesNo
Best atApplication logicBulk ops, heavy reporting

Key point: Saying 'Eloquent for app logic, query builder for bulk and reporting' is the balanced answer that avoids sounding dogmatic either way.

Q9. What are migrations and why use them?

Migrations are version-controlled PHP files that describe schema changes: creating tables, adding columns, indexes, and foreign keys. Running php artisan migrate applies pending ones; rollback reverses them via the down() method.

They let a whole team and every environment reach the same schema from code, without passing SQL scripts around. Combined with the schema builder, they keep database changes reviewable in pull requests like any other code.

php
public function up(): void
{
    Schema::create('posts', function (Blueprint $table) {
        $table->id();
        $table->string('title');
        $table->text('body');
        $table->boolean('published')->default(false);
        $table->timestamps();
    });
}

Q10. What is Blade and what makes it useful?

Blade is Laravel's templating engine. Templates compile to plain PHP and are cached, so there's no runtime overhead. It gives you clean directives (@if, @foreach, @auth), automatic output escaping with {{ }}, template inheritance, components, and slots.

The escaping matters: {{ $value }} escapes HTML by default to prevent XSS, while {!! $value !!} outputs raw and should be used only on trusted content. Components and layouts keep markup DRY across pages.

blade
@extends('layouts.app')

@section('content')
    @foreach ($posts as $post)
        <h2>{{ $post->title }}</h2>   {{-- escaped output --}}
    @endforeach
@endsection

Key point: Mentioning that {{ }} auto-escapes while {!! !!} does not is exactly the security awareness this question screens for.

Q11. What is middleware and give an example?

Middleware is a layer that inspects or filters HTTP requests as they enter and responses as they leave. Laravel ships middleware for authentication, CSRF protection, and trimming input; you assign them globally, to route groups, or to single routes.

A classic example is auth, which redirects unauthenticated users to login. You write custom middleware with make:middleware, put logic before or after $next($request), and register it in the kernel or route.

php
public function handle(Request $request, Closure $next)
{
    if (! $request->user()?->isAdmin()) {
        abort(403);
    }
    return $next($request);   // pass to the next layer
}

Q12. How does configuration and the .env file work in Laravel?

Configuration lives in the config directory as PHP files that return arrays. Those files read environment-specific values from the .env file through the env() helper, so secrets and per-environment values stay out of version control.

The rule: call env() only inside config files, and read values everywhere else through config('services.key'). That's because config caching (config:cache) freezes config and env() returns null outside it.

Key point: Knowing that env() returns null after config:cache unless it's called from a config file is a real production gotcha interviewers respect.

Q13. What are facades in Laravel?

A facade is a static-looking proxy to a service resolved from the container. Cache::get() looks like a static call, but under the hood it resolves the cache service from the container and calls the method on that instance.

Facades give a clean, memorable API while keeping the real object testable and swappable. You can always inject the underlying class instead if you prefer explicit dependencies, which some teams do for clarity.

php
use Illuminate\Support\Facades\Cache;

Cache::put('key', 'value', now()->addMinutes(10));
$value = Cache::get('key');

// equivalent via the container:
// app('cache')->put(...)

Q14. What are Eloquent relationships and name the common types?

Relationships define how models relate in the database and let you traverse them as properties. The common ones are hasOne, hasMany, belongsTo, belongsToMany (many-to-many via a pivot table), and the hasManyThrough and polymorphic variants for indirect and shared relations.

You declare them as methods on the model, then access them as dynamic properties. Laravel builds the joining queries for you based on naming conventions and the keys you specify.

php
class User extends Model
{
    public function posts()
    {
        return $this->hasMany(Post::class);
    }
}

class Post extends Model
{
    public function author()
    {
        return $this->belongsTo(User::class, 'user_id');
    }
}

$user->posts;      // collection of Post
$post->author;     // the owning User

Q15. How do you validate incoming request data?

The quickest way is $request->validate() in a controller, passing an array of rules; on failure Laravel redirects back with errors for web requests or returns a 422 JSON response for API requests. For anything reusable, put the rules in a Form Request class.

Rules are expressive strings or arrays (required, email, max:255, exists:users,id), and you can add custom rules and messages. Validation runs before your business logic, so invalid data never reaches it.

php
$validated = $request->validate([
    'title' => 'required|string|max:255',
    'email' => 'required|email|unique:users,email',
    'age'   => 'nullable|integer|min:18',
]);

// $validated holds only the validated fields

Q16. What is Tinker and when do you use it?

Tinker is an interactive REPL for your application, started with php artisan tinker. It boots the full app so you can run Eloquent queries, call services, and inspect objects live, exactly as they'd run in a request.

It's ideal for quickly checking a relationship, seeding a test record, or debugging why a query returns nothing, without writing a throwaway route.

bash
php artisan tinker
>>> User::count()
>>> User::first()->posts
>>> Post::factory()->count(5)->create()

Q17. What are Laravel Collections?

A Collection is a fluent, object-oriented wrapper around arrays, returned by most Eloquent queries. It gives you chainable methods (map, filter, reduce, pluck, groupBy, sortBy) that read far better than nested array functions.

Because methods return new collections, you can pipeline transformations cleanly. Eloquent results are collections, so the same tools work on database rows and plain arrays alike.

php
$names = Post::all()
    ->filter(fn ($p) => $p->published)
    ->sortByDesc('created_at')
    ->pluck('title');

// chainable, readable, returns a Collection

Q18. What are seeders and factories?

Factories define how to generate fake model instances with realistic data, using Faker. Seeders use factories (or explicit data) to populate the database, run via php artisan db:seed. Together they give you repeatable test and demo data.

This pairing is what makes testing practical: a test can spin up ten users with posts in one line, run against them, and roll back, without hand-writing fixtures.

php
// database/factories/PostFactory.php
public function definition(): array
{
    return [
        'title' => fake()->sentence(),
        'body'  => fake()->paragraph(),
    ];
}

// usage
Post::factory()->count(10)->create();

Q19. How does Laravel protect against CSRF attacks?

Laravel generates a per-session CSRF token and expects it on every state-changing request (POST, PUT, PATCH, DELETE). The VerifyCsrfToken middleware checks it; a mismatch returns a 419 error. In forms you output it with the @csrf directive.

For AJAX, the token goes in a header (X-CSRF-TOKEN), often read from a meta tag. API routes typically use token or Sanctum auth instead of session CSRF, so they can be excluded.

blade
<form method="POST" action="/posts">
    @csrf
    <input name="title">
    <button>Save</button>
</form>

Q20. How do you access request input in a controller?

Type-hint Illuminate\Http\Request in the controller method and Laravel injects it. Then read input with $request->input('key'), $request->only([...]), $request->all(), query params with $request->query(), and files with $request->file('avatar').

Prefer $request->input() or the validated data over raw superglobals, because the Request object normalizes JSON and form bodies and integrates with validation.

php
public function store(Request $request)
{
    $title = $request->input('title');
    $tags  = $request->input('tags', []);   // default if missing
    $file  = $request->file('cover');
}

Q21. What are named routes and why use them?

A named route attaches a stable name to a URL so you generate links by name, not by hardcoding the path. Then route('posts.show', $post) builds the URL, and changing the path later doesn't break every reference.

Named routes also power redirects (redirect()->route('login')) and make route definitions self-documenting. It's the difference between refactor-safe links and a find-and-replace hunt.

php
Route::get('/posts/{post}', [PostController::class, 'show'])->name('posts.show');

// generate the URL anywhere:
$url = route('posts.show', $post);   // /posts/42

Q22. How do sessions and flash messages work in Laravel?

Sessions store data across requests for a user, backed by a driver (file, cookie, database, Redis). You read and write with session('key') or the request. Flash data is session data that lives for exactly the next request, which is how success and error messages survive a redirect.

After a form submit you typically redirect with a flashed message and show it once on the next page. Laravel clears it automatically, so it doesn't reappear.

php
return redirect()
    ->route('posts.index')
    ->with('status', 'Post created');

// in the Blade view:
// @if (session('status')) {{ session('status') }} @endif

Q23. What role does Composer play in a Laravel project?

Composer is PHP's dependency manager, and Laravel itself is installed through it. It reads composer.json to know which packages a project needs, resolves compatible versions, and installs them into the vendor directory. The composer.lock file pins exact versions so every machine gets the same set.

It also generates the autoloader that lets you use any class without manual require calls. Running composer install rebuilds vendor from the lock file; composer update recomputes versions within your constraints.

bash
composer create-project laravel/laravel my-app   # new project
composer require laravel/sanctum                 # add a package
composer install                                 # install from lock file

Q24. How do you debug and log in Laravel?

For quick inspection there's dd() (dump and die, stops execution and shows a formatted value) and dump() (shows a value and keeps going). For anything that should persist, use the Log facade, which writes to storage/logs through configurable channels and levels.

In development you can add Telescope or Debugbar for request, query, and job insight. In production you send logs to a channel (a file, Slack, or an external service) at the right level, so you have a trail without dd() ever reaching users.

php
dd($user->toArray());          // dump and stop
dump($request->all());          // dump and continue

Log::info('Order placed', ['id' => $order->id]);
Log::error('Payment failed', ['user' => $user->id]);

Key point: Saying you'd never leave a dd() in committed code, and reach for Log for anything real, is the small maturity signal here.

Back to question list

Laravel Intermediate Interview Questions

Intermediate20 questions

For candidates with working experience: Eloquent depth, the container, queues, and the questions that separate users from understanders.

Q25. What is the N+1 query problem and how do you fix it?

N+1 happens when you load a collection of N parents, then access a relationship inside a loop, firing one extra query per parent: 1 query for the parents plus N for the relations. It's the most common Laravel performance bug and it hides in views that look innocent.

The fix is eager loading with with(): Laravel loads all the related records in one additional batched query instead of N. Use load() when you already have the collection, and lazy() or chunking for huge datasets.

php
// N+1: 1 + N queries
$posts = Post::all();
foreach ($posts as $post) {
    echo $post->author->name;   // one query per post
}

// fixed: 2 queries total
$posts = Post::with('author')->get();
foreach ($posts as $post) {
    echo $post->author->name;   // already loaded
}

Key point: Naming how you'd DETECT it (Laravel Debugbar, the query log, or preventLazyLoading in dev) is as valued as naming the fix.

Q26. What is the difference between eager and lazy loading?

Lazy loading fetches a relationship the first time you access it, one query at a time, which causes N+1 in loops. Eager loading fetches the relationships up front with with(), in a small fixed number of queries.

Lazy eager loading with load() sits in between: you already have the parent collection and want to load a relation on it in one query. Choose eager loading whenever you know you'll touch the relation for many records.

LazyEager (with)Lazy eager (load)
When it queriesOn first accessUp frontAfter retrieval, on demand
Query count for N parents1 + N22
Best atSingle recordLoops over manyAlready-fetched collection

Q27. What is the service container and how does dependency injection work?

The service container is Laravel's engine for resolving classes and their dependencies. When you type-hint a class in a constructor or controller method, the container builds it, recursively resolving whatever it needs. You rarely call new for services.

You teach it how to build things with bindings in a service provider: bind() for a fresh instance each time, singleton() for one shared instance, and interface-to-implementation bindings so you can swap concretes without touching callers.

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

// anywhere, the container injects StripeGateway:
public function __construct(private PaymentGateway $gateway) {}

Key point: Explaining bind vs singleton plus interface binding for swappability is the answer that indicates 'has actually structured an app', not just used one.

Q28. What are service providers and what goes in register vs boot?

Service providers are the bootstrapping classes where you wire services into the container. They have two phases: register() only binds things into the container, and boot() runs after every provider is registered, so it can safely use other services.

The rule that trips people up: never resolve a service inside register(), because the thing you need may not be bound yet. Event listeners, view composers, and route model bindings belong in boot().

php
public function register(): void
{
    $this->app->singleton(Reporter::class);   // only bind here
}

public function boot(): void
{
    View::share('appName', config('app.name'));   // safe to use services here
}

Key point: The 'don't resolve services in register()' rule is a common trip-up. Stating it in practice signals real provider experience.

Q29. How do queues and jobs work in Laravel?

Queues push slow work (sending email, processing images, calling third-party APIs) out of the request cycle so responses stay fast. You dispatch a job class, a queue worker (php artisan queue:work) picks it up and runs it in the background against a driver like Redis, database, or SQS.

Jobs are simple classes with a handle() method that can be retried, delayed, rate-limited, and batched. Failed jobs land in a failed_jobs table for inspection and retry.

php
class SendWelcomeEmail implements ShouldQueue
{
    public function __construct(public User $user) {}

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

SendWelcomeEmail::dispatch($user)->onQueue('mail');

How a queued job flows

1Dispatch
controller pushes the job onto a queue and returns immediately
2Store
the job serializes onto the driver (Redis, database, SQS)
3Worker picks up
queue:work pulls the next job and runs handle()
4Complete or retry
success removes it; failure retries, then lands in failed_jobs

The point is decoupling: the user's request never waits on the slow work.

Q30. How do events and listeners work, and when should you use them?

Events let you announce that something happened (OrderShipped) without the code that reacts being coupled to the code that fired it. Listeners subscribe to events and run the reaction; one event can have many listeners.

Use them to decouple side effects: fire OrderPlaced, and separate listeners send email, update inventory, and notify Slack, each testable in isolation. Queued listeners move that work off the request. Overusing events for straight-line logic hurts readability, so reach for them when decoupling genuinely helps.

php
event(new OrderPlaced($order));

class SendOrderConfirmation implements ShouldQueue
{
    public function handle(OrderPlaced $event): void
    {
        Mail::to($event->order->customer)->send(new OrderConfirmed($event->order));
    }
}

Q31. What are Form Request classes and why use them?

A Form Request is a dedicated class that holds validation rules and authorization for a specific request. You type-hint it in the controller method, and Laravel validates automatically before the method body runs, returning errors on failure.

It keeps controllers thin, makes rules reusable and testable, and puts authorization (authorize()) next to validation. For anything beyond a couple of inline rules, this is the maintainable choice.

php
class StorePostRequest extends FormRequest
{
    public function authorize(): bool
    {
        return $this->user()->can('create', Post::class);
    }
    public function rules(): array
    {
        return ['title' => 'required|max:255', 'body' => 'required'];
    }
}

// controller
public function store(StorePostRequest $request) { /* already validated */ }

Q32. What are API Resources and what problem do they solve?

API Resources are transformer classes that shape an Eloquent model into a JSON structure. They decouple your database schema from your API contract, so you choose exactly which fields appear, rename them, add computed values, and nest relations, without leaking internal columns.

They also handle collections and pagination consistently. Without them you either expose raw models (fragile, over-sharing) or hand-build arrays (repetitive).

php
class PostResource extends JsonResource
{
    public function toArray($request): array
    {
        return [
            'id'     => $this->id,
            'title'  => $this->title,
            'author' => $this->whenLoaded('author', fn () => $this->author->name),
        ];
    }
}

return PostResource::collection($posts);

Q33. What are Laravel's authentication options and when do you use each?

Laravel offers session-based auth for traditional web apps (starter kits like Breeze and Jetstream scaffold it), Sanctum for SPA and mobile token auth on first-party clients, and Passport for full OAuth2 when third parties need to authorize.

The judgment call: Breeze or Jetstream for server-rendered apps, Sanctum for your own SPA or mobile app hitting your API, Passport only when you actually need OAuth2 authorization flows. Reaching for Passport by default is the common overkill mistake.

ToolBest forAuth style
Breeze / JetstreamServer-rendered web appsSession cookies
SanctumFirst-party SPA and mobileAPI tokens / cookie
PassportThird-party OAuth2 clientsFull OAuth2 server

Key point: Saying 'Sanctum for first-party, Passport only when you need OAuth2' is the concise answer that avoids the reach-for-Passport reflex.

Watch a deeper explanation

Video: Laravel 8 REST API With Sanctum Authentication (Traversy Media, YouTube)

Q34. What is the difference between gates and policies?

Both handle authorization. Gates are closures for simple, one-off checks not tied to a model (can this user access the admin dashboard?). Policies are classes that group authorization logic around a specific model, one method per action (view, update, delete a Post).

Use policies when authorization is per-model and has several actions, which is most CRUD. Use gates for coarse, model-free checks. Both plug into the same $user->can(...) and authorize() calls.

php
class PostPolicy
{
    public function update(User $user, Post $post): bool
    {
        return $user->id === $post->user_id;
    }
}

// in a controller
$this->authorize('update', $post);   // 403 if the policy denies

Q35. What are query scopes in Eloquent?

Scopes package reusable query constraints on a model. A local scope is a method prefixed with scope that you call fluently (Post::published()), keeping common where-clauses in one place instead of repeating them across the codebase.

Global scopes apply a constraint to every query on a model automatically, which is how soft deletes and multi-tenant filtering work. The trade-off with global scopes is that they can surprise you, so they're worth documenting.

php
class Post extends Model
{
    public function scopePublished($query)
    {
        return $query->where('published', true);
    }
}

Post::published()->latest()->get();

Q36. What are accessors, mutators, and attribute casts?

Accessors transform an attribute when you read it, mutators transform it when you write it, letting a model present clean values while storing raw ones. Casts do the same declaratively for common types: casting a column to boolean, array, datetime, or an enum.

Modern Laravel unifies accessor and mutator into a single Attribute method. Casts handle the routine conversions (JSON columns to arrays, timestamps to Carbon), while accessors handle custom logic like formatting a full name.

php
protected function casts(): array
{
    return ['published' => 'boolean', 'meta' => 'array', 'published_at' => 'datetime'];
}

protected function fullName(): Attribute
{
    return Attribute::get(fn () => "{$this->first} {$this->last}");
}

Q37. How do many-to-many relationships and pivot tables work?

A many-to-many relationship (a User has many Roles and a Role has many Users) needs a pivot table in the middle, conventionally named from the two singular table names alphabetically (role_user). You declare belongsToMany on both models.

The pivot table can carry extra columns (like assigned_at), which you expose with withPivot(). Attach, detach, and sync manage the links: sync() replaces the whole set to match an array of IDs, which is what checkbox forms usually want.

php
class User extends Model
{
    public function roles()
    {
        return $this->belongsToMany(Role::class)->withPivot('assigned_at');
    }
}

$user->roles()->attach($roleId);
$user->roles()->sync([1, 2, 3]);   // set roles to exactly these

Q38. What are soft deletes and how do they work?

Soft deletes mark a row as deleted with a deleted_at timestamp instead of removing it. Add the SoftDeletes trait and a deleted_at column, and Eloquent automatically hides soft-deleted rows from normal queries via a global scope.

You recover them with restore(), include them with withTrashed(), or query only them with onlyTrashed(). Use forceDelete() to remove permanently. It's the standard way to keep an audit trail and allow undo.

php
use Illuminate\Database\Eloquent\SoftDeletes;

class Post extends Model
{
    use SoftDeletes;   // needs a deleted_at column
}

$post->delete();                 // sets deleted_at
Post::withTrashed()->find($id);  // include soft-deleted
$post->restore();                // bring it back

Q39. How do you use database transactions in Laravel?

DB::transaction() wraps a set of queries so they all commit together or all roll back on any exception, keeping data consistent. It's the right tool whenever a single logical operation touches multiple tables, like creating an order and its line items.

The closure form auto-commits on success and auto-rolls-back if an exception is thrown, and it retries on deadlock a configurable number of times. For manual control there's DB::beginTransaction(), commit(), and rollBack().

php
DB::transaction(function () use ($cart) {
    $order = Order::create(['total' => $cart->total()]);
    $order->items()->createMany($cart->lineItems());
    Inventory::decrement($cart->skus());
    // any exception here rolls the whole thing back
});

Q40. How does caching work in Laravel?

The Cache facade gives a unified API over drivers (Redis, Memcached, database, file). You store values with a TTL, retrieve them, and the remember() helper computes-and-caches in one call: if the key is missing it runs the closure, stores the result, and returns it.

Beyond the application cache, Laravel caches config, routes, views, and events for production speed. The eternal caching problem stays: invalidation. Key cache entries carefully and clear or tag them when the underlying data changes.

php
$stats = Cache::remember('dashboard.stats', now()->addMinutes(10), function () {
    return expensiveDashboardQuery();
});

Cache::forget('dashboard.stats');   // invalidate on data change

Q41. How do you test a Laravel application?

Laravel ships with a testing setup on top of PHPUnit (and Pest as a popular alternative). Feature tests exercise real HTTP routes with helpers like $this->get('/posts')->assertOk(), while unit tests check classes in isolation. Factories and a fresh test database make each test self-contained.

The RefreshDatabase trait migrates and rolls back around each test so state never leaks. You assert on responses, database rows (assertDatabaseHas), sent mail, dispatched jobs, and events, all with expressive helpers.

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

    $this->actingAs($user)
        ->post('/posts', ['title' => 'Hi', 'body' => 'There'])
        ->assertRedirect();

    $this->assertDatabaseHas('posts', ['title' => 'Hi']);
}

Q42. How does task scheduling work in Laravel?

Laravel's scheduler lets you define recurring tasks in code (in the console schedule) with a fluent frequency API: daily(), everyFiveMinutes(), cron() for custom expressions. You register a single cron entry on the server that runs schedule:run every minute, and Laravel decides what's due.

This beats scattering many crontab lines: schedules live in version control, can be conditional, avoid overlaps with withoutOverlapping(), and run on one queue. Tasks can be Artisan commands, closures, or queued jobs.

php
// one server crontab line:
// * * * * * cd /app && php artisan schedule:run >> /dev/null 2>&1

$schedule->command('reports:daily')->dailyAt('02:00');
$schedule->job(new PruneOldLogs)->weekly()->withoutOverlapping();

Q43. Why use Collections over plain PHP arrays?

Collections give a chainable, readable API over the same data an array holds. Instead of nesting array_map inside array_filter and losing the reading order, you write a top-to-bottom pipeline of map, filter, and reduce that mirrors how you think about the transformation.

They also carry helpful methods arrays lack (groupBy, pluck, partition, sum by key) and return collections so chaining stays fluent. On huge datasets, LazyCollection streams instead of holding everything in memory.

php
collect($orders)
    ->groupBy('customer_id')
    ->map(fn ($group) => $group->sum('total'))
    ->sortDesc();

Q44. What do config:cache and route:cache do, and when do you use them?

config:cache merges every config file into one cached file so the framework doesn't parse them all on each request; route:cache compiles route registration into a fast lookup. Both cut per-request overhead noticeably and belong in production deploys.

The catch: after config:cache, env() returns null outside config files, and route:cache breaks if you use closure-based routes (they can't serialize). Clear them in development with config:clear and route:clear so changes take effect.

Key point: Naming the two gotchas (env() null after config cache, no closure routes with route cache) is what separates 'ran the command once' from 'debugged it in production'.

Back to question list

Laravel Interview Questions for Experienced Developers

Experienced16 questions

advanced rounds probe internals, design judgment, and production scars. Expect every answer here to draw a follow-up.

Q45. How does the service container resolve and build a dependency?

When you ask the container for a class, it checks for an explicit binding first; if none exists it uses reflection to inspect the constructor, recursively resolves each type-hinted dependency, and instantiates the class. Singletons are cached after the first build; regular bindings rebuild each time.

Contextual bindings let the same interface resolve to different concretes depending on the consuming class, and interface-to-implementation bindings make the whole app swappable. Understanding this is why you can type-hint an interface and never call new.

Key point: reflection-based autowiring and contextual bindings matters.

Q46. When do you choose middleware, events, or a service class for logic?

Middleware belongs to HTTP concerns that wrap the request: auth, rate limiting, header manipulation, logging. Events and listeners belong to decoupled side effects triggered by domain actions (order placed sends mail, updates inventory). Service classes hold the core business logic that controllers call.

The failure mode is stuffing business logic into middleware because it's convenient, or firing events for straight-line code that would read better as a direct call. Match the tool to whether the concern is transport, a decoupled reaction, or the operation itself.

Q47. Should you use the repository pattern with Eloquent?

It depends, and having a real opinion matters here. Eloquent is already an abstraction over the database, so wrapping every model in a repository often adds a layer that hides Eloquent's expressive query methods and buys little, since you'll almost never swap the ORM.

Where a repository or a query-object earns its place: consolidating a genuinely complex query used in many spots, or defining a domain boundary in a large app where you want to keep Eloquent out of the domain layer. Blanket repositories over simple CRUD are usually cargo-culted from other ecosystems.

Key point: A crisp 'usually no, here's when yes' beats a rehearsed pro-repository sermon; the question needs to see you weigh trade-offs.

Q48. How do you process millions of rows without exhausting memory?

Never load everything with get(): it hydrates every row into memory at once. Use chunk() or chunkById() to process fixed-size batches, cursor() to stream one hydrated model at a time via a generator, or lazy() for a LazyCollection you can pipeline.

chunkById() is safer than chunk() when you're modifying rows during iteration, because plain chunk() paginates by offset and skips or repeats rows when the result set shifts under you. For pure reads, cursor() keeps memory flat.

php
User::where('active', true)->chunkById(1000, function ($users) {
    foreach ($users as $user) {
        ExportUser::dispatch($user);
    }
});

// streaming alternative, one model at a time:
foreach (User::lazy() as $user) { process($user); }

Key point: Knowing WHY chunkById beats chunk when mutating rows (offset drift) is the detail that marks real large-dataset experience.

Q49. How do you make queued jobs reliable in production?

Make jobs idempotent so a retry can't double-charge or double-send, set sensible tries and backoff, and use a durable driver (Redis or SQS, not sync) with a supervised worker (Supervisor or Horizon) that restarts on crash. Monitor the failed_jobs table and alert on it.

Guard against long jobs blocking the queue with timeouts, prevent duplicate concurrent runs with WithoutOverlapping or unique jobs, and separate high and low priority work onto different queues so a flood of one doesn't starve the other.

RiskMitigation
Double processing on retryIdempotent handle() logic
Worker crashesSupervisor / Horizon restarts it
One queue starves othersPriority queues, dedicated workers
Silent failuresMonitor failed_jobs, alerting

Q50. What is Laravel Horizon and when do you reach for it?

Horizon is a dashboard and configuration layer for Redis-backed queues. It gives real-time metrics (throughput, wait times, failures), tag-based job monitoring, auto-balancing of workers across queues, and code-driven worker configuration instead of hand-tuned Supervisor files.

Reach for it once queues are load-bearing: you want visibility into what's slow, alerts on failures, and the ability to scale workers per queue by config. On a small app with light queues, plain queue:work under Supervisor is enough.

Q51. Beyond N+1, how do you optimize Eloquent-heavy code?

Select only the columns you need instead of full rows, add database indexes on the columns you filter and join on, and use exists() or count() instead of loading collections just to check presence. Constrain eager loads with closures so you don't pull relations you won't use.

For aggregates, push work to the database (withCount, withSum, groupBy) rather than summing in PHP. For read-heavy hot paths, cache the computed result. And always confirm with the query log or a profiler rather than guessing which query is the bottleneck.

php
$authors = User::select('id', 'name')
    ->withCount('posts')
    ->with(['posts' => fn ($q) => $q->select('id', 'user_id', 'title')->latest()->limit(5)])
    ->get();

Q52. What are polymorphic relationships and when are they the right tool?

A polymorphic relationship lets one model belong to more than one other model type on a single association. A Comment can belong to a Post or a Video through a morphTo relation, using two columns: commentable_id and commentable_type.

They fit genuinely shared concerns: comments, likes, images, tags across many parent types. The cost is weaker foreign-key integrity (the type column isn't a real FK) and trickier queries, so use them when the shared behavior is real, not just to avoid a couple of tables.

php
class Comment extends Model
{
    public function commentable()
    {
        return $this->morphTo();
    }
}

class Post extends Model
{
    public function comments()
    {
        return $this->morphMany(Comment::class, 'commentable');
    }
}

Q53. How do you write a custom attribute cast, and why?

Implement CastsAttributes with get() and set() to convert a stored value to and from a rich object. This centralizes a transformation so every place that touches the attribute gets the object form (a value object, an encrypted field, a money type) without repeating logic.

It's cleaner than accessors and mutators when the same conversion applies across many models, and it keeps the model's storage concern separate from how the rest of the app uses the value.

php
class MoneyCast implements CastsAttributes
{
    public function get($model, $key, $value, $attributes)
    {
        return new Money($value);          // cents to Money object
    }
    public function set($model, $key, $value, $attributes)
    {
        return $value->cents();            // Money object back to cents
    }
}

// model: protected $casts = ['price' => MoneyCast::class];

Q54. What are macros in Laravel and when would you use one?

Many Laravel classes (Collection, Str, Request, the query builder, Response) are macroable: you register a closure with ::macro() and it becomes callable as if it were a native method. It's the sanctioned way to add reusable helpers to framework classes without extending them.

Register macros in a service provider's boot method. Use them for genuinely reusable extensions (a domain-specific collection method used everywhere), but keep them discoverable and documented, since a macro that appears from nowhere confuses the next developer.

php
// in a service provider boot()
Collection::macro('toUpper', function () {
    return $this->map(fn ($v) => strtoupper($v));
});

collect(['a', 'b'])->toUpper();   // ['A', 'B']

Q55. How would you design multi-tenancy in a Laravel application?

Clarify the isolation requirement first, then pick a model. Single database with a tenant_id column and a global scope is simplest and cheapest, isolation is logical. A database per tenant gives stronger isolation and easier per-tenant backups at higher operational cost. A schema per tenant sits in between on Postgres.

For the shared-database approach, a global scope plus a resolved current-tenant binding keeps every query filtered automatically, and you guard against cross-tenant leaks in tests. The right choice depends on compliance needs, tenant count, and how customizable per tenant the data must be.

StrategyIsolationCost / complexity
Shared DB + tenant_idLogical (scope)Low
Schema per tenantStrongerMedium
Database per tenantStrongestHigh (migrations, backups per tenant)

Key point: Leading with 'what isolation and compliance do we need?' before naming a strategy is exactly the design-question behavior the technical evaluation checks.

Q56. How do you version and structure a large Laravel API?

Version at the URL prefix (v1, v2) or via a header, keeping controllers and API Resources namespaced per version so a breaking change lives in its own set of classes. Route groups apply shared middleware, and API Resources pin the response contract so schema changes don't silently break clients.

Structure the app so business logic lives in service or action classes that both versions can call, and only the thin controller and resource layer differs. Deprecate old versions on a schedule with clear communication rather than maintaining them forever.

Q57. How do you detect N+1 and other query problems before production?

In development, enable Model::preventLazyLoading() so any lazy load throws immediately, turning silent N+1 into a loud test failure. Laravel Debugbar or Telescope surface query counts and durations per request, and DB::listen or enableQueryLog() logs the actual SQL.

In CI, assert query counts on critical endpoints so a regression fails the build. In production, Telescope (guarded) or an APM tool flags slow queries. The theme: make the invisible visible early, because query problems rarely show up until data grows.

php
// in AppServiceProvider boot(), non-production only
Model::preventLazyLoading(! app()->isProduction());

// assert query count in a test
DB::enableQueryLog();
$this->get('/dashboard');
$this->assertLessThan(10, count(DB::getQueryLog()));

Q58. What are model events and observers, and what's the risk?

Eloquent fires events around a model's lifecycle (creating, created, updating, saving, deleting). Observers group listeners for these into one class, so you can auto-set a slug on creating or clean up files on deleting without cluttering the model.

The risk is hidden side effects: logic in observers fires on every save from anywhere, including seeders, tinker, and bulk operations, and mass updates like Model::where(...)->update() bypass model events entirely. Overloaded observers make behavior hard to trace, so keep them thin and know what skips them.

Key point: Naming that query-builder bulk updates skip model events is the gotcha that catches people who rely on observers for critical invariants.

Q59. A Laravel endpoint is slow in production. Walk through your debugging approach.

Observe first: check logs and any APM for the slow route, then look at query count and duration for that request (Telescope, slow-query log). The usual suspects are N+1 queries, a missing index, an un-cached expensive computation, or a synchronous call to a slow external service that should be queued.

Form a hypothesis, confirm it with a measurement (not a guess), fix at the right layer, and verify the improvement with the same measurement. The structure, observe, hypothesize, verify, fix, confirm, matters more than any single tool.

Key point: The methodology is; tools support the evidence.

Q60. Design question: how would you build a URL shortener in Laravel?

Clarify scale and features first (redirect volume, custom aliases, analytics, expiry). Core model: a links table storing the short code and target URL with a unique index on the code. Generation can be a base62 encoding of the auto-increment id or a random collision-checked code; encoding the id avoids lookups.

The redirect route resolves the code to a URL and issues a 301 or 302. Put the code lookup behind a cache (Redis) since it's read-heavy, queue click-tracking so the redirect stays fast, and rate-limit creation. Close on the operational edges: reserved words, expired links, and what to serve on a miss.

php
Route::get('/{code}', function (string $code) {
    $url = Cache::remember("link:$code", 3600, fn () =>
        Link::where('code', $code)->value('target')
    );
    abort_if(! $url, 404);
    TrackClick::dispatch($code);   // queued, non-blocking
    return redirect()->away($url, 301);
});

Key point: Structuring the answer clarify, data model, generation, redirect path, operational edges is what the design question is really scoring.

Back to question list

Why Laravel? Laravel vs Symfony, Rails, and Node/Express

Laravel wins when you want a full-stack PHP framework that gives you productivity out of the box: convention over configuration, a rich ORM, and first-party tooling for queues, auth, and testing. It trades some of Symfony's configurability for speed of delivery, and it runs on PHP, which shapes hiring and hosting. Where it competes with Rails, the mental model is close (both are opinionated, ActiveRecord-style, convention-heavy). Against Node/Express, Laravel gives you structure and an ORM by default, while Express hands you a minimal core and asks you to assemble the rest. Saying these trade-offs out loud is itself an interview signal: it shows you pick tools on merits, not habit.

FrameworkLanguageBest atWatch out for
LaravelPHPFull-stack apps, fast delivery, rich ORMPHP runtime constraints, heavier than micro-frameworks
SymfonyPHPConfigurable enterprise systems, reusable componentsSteeper setup, more boilerplate
Ruby on RailsRubyConvention-driven apps, mature ecosystemRuby hosting/hiring pool, runtime speed
Express (Node)JavaScriptLightweight APIs, shared JS stackNo ORM or structure by default, assemble it yourself

How to Prepare for a Laravel Interview

Prepare in layers, and practice out loud. Most Laravel rounds move from concept questions to live coding to a design or debugging discussion, so rehearse each stage rather than only reading answers.

  • Master your tier's concepts until you can explain them without notes, then read one tier up for the stretch questions.
  • Type and run every snippet in a fresh Laravel app; wiring a real route, model, and migration cements it far faster than reading.
  • Practice thinking aloud on small problems with a timer, because your process, not just the final answer is the technical point.
  • Take the quiz on this page to find weak spots, then revisit those questions before the real round.

The typical Laravel interview flow

1Recruiter or phone screen
background, motivation, a few concept checks
2Technical concepts
request lifecycle, Eloquent, middleware, the service container
3Live coding
build a route, model, and controller under observation
4Design or debugging
trade-offs, N+1 hunting, reading unfamiliar code, follow-ups

Earlier rounds increasingly run as AI coding interviews. The concepts on this page are what gets probed at every stage.

Test Yourself: Laravel Quiz

Ready to test your Laravel knowledge?

10 questions, about 6 minutes. Score 70% or higher to earn a shareable certificate.

10 questions Instant feedback Free certificate on 70%+

Frequently  Asked  Questions

Which Laravel topics should I prioritize before a technical round?

Prioritize the areas that change real decisions: fundamentals, practical tasks, debugging, trade-offs, and evidence. The highest-value questions are tied to a project example, a validation check, or a failure mode.

Are these questions enough to pass a Laravel interview?

They cover the question-answer portion well, but most Laravel rounds also include live coding: wiring a route, model, and controller while explaining your thinking. building small features out loud with a timer is the practice path. Our AI coding interview prep guide covers that format, including how automated evaluation reads your process.

Which Laravel version do these answers assume?

Modern Laravel, roughly versions 10 and 11. The core ideas (Eloquent, Blade, the container, middleware) have been stable for years, so version-specific syntax rarely decides a round. When a detail is version-sensitive, say which version you're answering for and note that the concept carries across.

How long does it take to prepare for a Laravel interview?

If you use Laravel at work or in study, one to two weeks of an hour a day covers this bank with practice runs. Starting colder, plan three to four weeks and build small apps daily; reading answers without running code is how preparation quietly fails.

Do interviewers ask exactly these questions?

The concepts repeat far more reliably than the exact wording. Interviewers rephrase, chain follow-ups, and push toward whatever you claim confidence in. Prepare the underlying ideas: the request lifecycle, Eloquent relationships, the N+1 problem, middleware, and service providers, and the phrasing takes care of itself.

Is there a way to test my Laravel knowledge?

Yes. The quiz on this page scores you as you go and explains every answer, so you find your weak spots fast. Pass the threshold and you can download a shareable certificate with your name and score, free and with no sign-up. It's the quickest way to check yourself before the real round.

From the team that builds coding interviews

Hyring builds the AI Coding Interviewer that runs live technical rounds in 20+ languages for 5,000+ hiring teams. These Laravel questions and scoring notes reflect what actually gets asked and evaluated inside the interviews we host.

See how the AI Coding Interviewer works

Sources

Adithyan RKWritten by Adithyan RK
Surya N
Fact-checked by Surya N
Published on: 2 Jun 2026Last updated: 2 Jul 2026
Share: