TL;DR: Laravel interviews in 2026 test the service container, Eloquent performance, queues and the security defaults. Candidates should know that Laravel 13 requires PHP 8.3 or later, and that Laravel 11 removed the HTTP and console kernels from new apps in favour of a single bootstrap/app.php file.
Laravel 13 shipped on March 17, 2026, and it raised the minimum PHP version to 8.3. It also added a first-party AI SDK, JSON:API resources and queue routing by class.
The upgrade was small by design, so most interview topics are the ones that mattered two years ago: the container, Eloquent, queues and testing.
The difference is that a 2026 answer should use the current structure, not the kernel files older tutorials still show.
- 1Current versions as of September 2026: Laravel 13.33 and PHP 8.5.11, with PHP 8.6 at its second release candidate.
- 2Laravel 12 stopped getting bug fixes on August 13, 2026. It gets security fixes until February 24, 2027.
- 3Breeze and Jetstream no longer receive updates. New apps start from the React, Svelte, Vue or Livewire starter kits.
- 4Laravel 13's CSRF middleware now checks the browser's
Sec-Fetch-Siteheader first and falls back to the token.
Container and Lifecycle
1. What is the service container, and what is the difference between binding and resolving?
The service container is the object that builds your classes and injects their dependencies. Binding tells it how to build something. Resolving asks it for an instance.
bind()builds a new instance on every resolve.singleton()builds once and returns the same instance for the life of the app.scoped()builds once per request or job. It matters under Octane and queue workers, where the app lives across many requests.
Concrete classes need no binding at all: the container reads the constructor's type hints and builds them. You bind only interfaces, primitives and objects that need custom setup. See the service container docs.
2. What is the difference between a service provider's register() and boot() methods?
register() only binds things into the container. boot() runs after every provider has registered, so it can use any service.
Resolving a service inside register() is a classic bug: the service you need may belong to a provider that has not registered yet. Event listeners, route model bindings, gates, macros and Model::preventLazyLoading() all belong in boot().
Since Laravel 11, your own providers are listed in bootstrap/providers.php, and a new app ships with just AppServiceProvider.
3. Walk through the lifecycle of an HTTP request in Laravel.
Every request enters through public/index.php, which loads the Composer autoloader and gets the application from bootstrap/app.php.
The HTTP kernel then runs its bootstrappers, which load configuration, detect the environment and set up error handling and logging.

Next come the service providers: all register() methods, then all boot() methods. The request passes through global middleware to the router, which runs route middleware and calls the controller.
The response travels back out through the same middleware. The request lifecycle page describes each step.
4. What is contextual binding?
Contextual binding gives different classes different implementations of the same interface. A photo controller can get the local disk while a video controller gets S3.
$this->app->when(PhotoController::class)
->needs(Filesystem::class)
->give(fn () => Storage::disk('local'));
For common cases, contextual attributes do the same job on the parameter itself. #[Storage('local')] Filesystem $files or #[Config('app.timezone')] string $tz needs no provider code.
A strong candidate knows both and prefers the attribute when it fits.
5. Facades, helpers or constructor injection: which should you use?
All three reach the same container services, so the choice is about readability and tests. A facade such as Cache::get() looks static but forwards the call to an object it resolves from the container. A helper such as cache() does the same.
Constructor injection makes a class's dependencies visible in its signature, which suits services and actions.
Facades are fine in controllers and routes, and they are easy to fake: Queue::fake() or Mail::fake() swaps the real service in one line. The warning sign is a class that uses ten facades, which hides how much it depends on.
Eloquent and Data
6. What is the N+1 query problem, and how do you prevent it in Laravel?
N+1 happens when you load N parent models in one query and then lazy-load a relation for each one, which adds N more queries. Eager loading fixes it: Post::with('author')->get() runs two queries no matter how many posts there are.
Two settings help catch it. Model::preventLazyLoading(! app()->isProduction()) throws an exception on any lazy load outside production.
Since Laravel 12.8, Model::automaticallyEagerLoadRelationships() can also eager-load a relation for the whole collection the first time one model touches it. See Eloquent relationships.
7. How do polymorphic relationships work, and what is a morph map?
A polymorphic relation lets one model belong to several parent types through two columns. A Comment can belong to a Post or a Video using commentable_id and commentable_type.
The child uses morphTo(); each parent uses morphMany() or morphOne().
By default the type column stores the full class name, such as App\Models\Post. Renaming the class then breaks every stored row.
Relation::enforceMorphMap(['post' => Post::class]) stores a short alias instead, and it throws if a model has no alias. A senior candidate sets it up on day one.
8. What is the difference between a global scope and a local scope?
A global scope adds a constraint to every query on a model automatically. A local scope is a named constraint you apply by hand.
SoftDeletes is the best-known global scope: it adds whereNull('deleted_at') to every query. Local scopes read like query methods, as in User::popular()->active()->get().
The current docs define them with a #[Scope] attribute on a protected method; older codebases use the scopePopular() naming style. Global scopes surprise people, so remove one explicitly with withoutGlobalScope() when you need all rows.
9. How do you write accessors and mutators in current Laravel?
Define one protected method named after the attribute that returns an Attribute object. The old getFirstNameAttribute() and setFirstNameAttribute() pair is the legacy style.
protected function firstName(): Attribute
{
return Attribute::make(
get: fn (string $value) => ucfirst($value),
set: fn (string $value) => strtolower($value),
);
}
For type conversion, casts are simpler: 'is_admin' => 'boolean', 'options' => 'array', or an enum class. Password hashing is usually the 'hashed' cast rather than a hand-written mutator.
10. What is mass assignment, and how does Laravel guard against it?
Mass assignment is filling a model from an array, such as User::create($request->all()). Without a guard, an attacker could add is_admin=1 to the form and set a column you never meant to expose.
Laravel only fills attributes listed in $fillable (or not listed in $guarded). Unlisted keys are dropped silently, which can hide bugs.
Model::preventSilentlyDiscardingAttributes() makes them throw instead, which is worth enabling outside production. The safest habit is to pass $request->validated(), never $request->all().
11. How do you use database transactions, and what goes wrong with jobs inside them?
DB::transaction(fn () => ...) commits if the closure returns and rolls back if it throws. A second argument, attempts: 5, retries the closure when the database reports a deadlock.
The trap is dispatching a job or event inside the transaction. A fast worker can pick up the job before the commit, then fail to find the row.
Mark the job with afterCommit(), or implement ShouldDispatchAfterCommit on the event, so it waits for the commit and is dropped on rollback.
12. What are API resources for?
API resources turn models into JSON in a controlled way, so the response shape does not depend on the table's columns. A UserResource lists exactly which fields leave the server.
$this->whenLoaded('posts') includes a relation only if it was eager loaded, which prevents a resource from causing N+1 queries. $this->when($user->isAdmin(), ...) adds fields conditionally.
Laravel 13 also added first-party JSON:API resources for teams that must follow that specification.
Queues and Performance
13. How does the queue system work, and why must workers restart after a deploy?
You dispatch a job; Laravel serializes it and stores it in a queue backend such as Redis, SQS or the database. A worker started with php artisan queue:work pulls jobs and runs each job's handle() method.
Workers are long-lived processes that boot the app once and keep your code in memory.
After a deploy they keep running the old code until restarted. php artisan queue:restart tells each worker to exit after its current job so the process manager (Supervisor, or Horizon for Redis) starts a fresh one.
14. How do you handle a job that keeps failing?
Set a retry limit and a backoff, and handle the final failure. After the last attempt, Laravel moves an asynchronous job to the failed_jobs table.
$triesand$backoffon the job, or--trieson the worker. Laravel 13 adds#[Tries]and#[Backoff]attributes for the same settings.- A
failed(Throwable $e)method for cleanup or alerts. php artisan queue:failedto list failures andqueue:retryto run them again after a fix.
Jobs dispatched synchronously never reach failed_jobs; their exception is thrown straight back. Because retries happen, a strong candidate also makes the job idempotent. See the queues docs.
15. What is the difference between a job chain and a job batch?
A chain runs jobs one after another and stops if one fails. A batch runs jobs in parallel and lets you react when they finish.
Bus::chain([...]) suits steps that depend on each other, such as download, then resize, then publish. Bus::batch([...]) suits independent work such as importing 500 CSV chunks.
It offers then, catch and finally callbacks and tracks progress in a job_batches table.
16. How do you stop the same job from running twice at once?
Implement ShouldBeUnique to keep a second copy off the queue while one is pending. Use the WithoutOverlapping job middleware when copies may queue but must not run at the same time.
Both rely on atomic cache locks, so the cache driver must support locks (Redis, Memcached, database or DynamoDB), and every server must share it. A unique job can define uniqueId() to be unique per record rather than per class.
17. What does Laravel Octane change, and what breaks under it?
Octane boots the app once and keeps it in memory, then feeds it many requests. It runs on FrankenPHP, Swoole, Open Swoole or RoadRunner, and it removes the per-request bootstrap cost of PHP-FPM.
The cost is shared state. A singleton that captured the request or the config in its constructor keeps that stale value for every later request. Static arrays that grow per request leak memory.
A candidate who has shipped Octane will mention scoped() bindings, resolving the request inside methods, and --max-requests to recycle workers. See the Octane docs.
18. Which caches do you turn on in production, and what is the env() trap?
Run php artisan optimize on deploy, which caches config, routes, events and views. Use Cache::remember() for expensive queries and API calls.
env('STRIPE_KEY') in a controller then returns null in production. Read env values only in config files, and use config() everywhere else.Security and Design
19. Sanctum or Passport: which do you pick?
Pick Sanctum unless you must run an OAuth2 server. The Passport docs say so directly: use Passport if the app "absolutely needs to support OAuth2".
- Cookie sessions for your own SPA
- Personal API tokens with abilities
- No OAuth2
- Full OAuth2 server
- Authorization code with PKCE, client credentials, device grant
- For third-party apps acting for your users
A first-party SPA on the same top-level domain should use Sanctum's cookie mode, not tokens in local storage, because cookies are not readable by injected scripts.
20. How does Blade protect against XSS, and where can it still leak?
Blade's {{ $value }} escapes output with htmlspecialchars, so injected tags print as text. {!! $value !!} prints raw HTML and should only ever receive trusted or sanitized content.
Escaping for HTML is not escaping for every context. A value placed in a href can still be a javascript: URL, and a value placed inside a script block needs Js::from() or @json. Good candidates name the context, not just the syntax.
21. When do you use a gate, and when a policy?
Gates are closures for checks that are not about one model, such as "can view the admin dashboard". Policies are classes that group the checks for one model, such as PostPolicy::update().
The docs compare them to routes and controllers, and most apps use both. Controllers call Gate::authorize('update', $post), Blade uses @can, and form requests can authorize in their authorize() method.
Laravel 13 also adds an #[Authorize] attribute for controller methods.
22. How are events and listeners registered in current Laravel?
They are discovered automatically. Laravel scans the app/Listeners directory and registers any handle or __invoke method for the event class in its type hint.
The EventServiceProvider that older answers mention is no longer in a new app. A listener that implements ShouldQueue runs on the queue, which keeps slow side effects such as emails out of the request.
Run php artisan event:list to see what was discovered.
23. Should a Laravel app use the repository pattern?
Usually not as a default. Eloquent already is a data-access layer, and a repository that only wraps find() and all() adds files without adding a boundary.
Repositories earn their place when the data source really varies, or when complex queries need one tested home. Many teams get more from small single-purpose action classes, such as CreateInvoice, called from controllers, jobs and commands.
The interview signal is a reason, not a pattern name.
Testing
24. What is the difference between a feature test and a unit test in Laravel?
A feature test boots the framework and exercises a slice of the app, usually through HTTP: $this->post('/orders', $data)->assertCreated(). A unit test checks one class in isolation, without the framework or the database.
Most Laravel test suites are mostly feature tests because they catch wiring bugs in routes, middleware and validation. Pure business logic, such as a price calculator, is faster to cover with unit tests.
Laravel supports both Pest and PHPUnit.
25. What exactly does the RefreshDatabase trait do?
It migrates the test database once if the schema is out of date, then wraps each test in a transaction that is rolled back afterwards. It does not re-run migrations before every test.
The database testing docs note the side effect: rows written by tests that do not use the trait can remain. DatabaseMigrations and DatabaseTruncation give a full reset but are much slower.
26. How do you test code that calls external services?
Fake them. Http::fake() returns canned responses for matching URLs, and Http::preventStrayRequests() makes any unfaked request throw, so a test can never hit a real API by accident.
The same approach covers the rest of the framework: Queue::fake(), Mail::fake(), Event::fake(), Storage::fake() and Notification::fake(). After acting, you assert, as in Queue::assertPushed(SendInvoice::class).
PHP for Laravel
27. What does declare(strict_types=1) do?
It turns off type coercion for scalar parameter and return types in that file. Passing "5" to an int parameter then throws a TypeError instead of converting it.
The directive applies to calls made from the file where it is declared, and it must be the first statement. It does not change how PHP compares values, and it does not affect code in other files.
28. How do you process a million rows without running out of memory?
Stream them instead of loading them. Model::lazy() queries in chunks behind the scenes and yields a LazyCollection, so memory stays flat.
chunkById() is the safe choice when the loop updates the rows it reads, because offset-based chunk() can skip rows as the result set changes.
LazyCollection is built on PHP generators, which yield one value at a time instead of building an array. For a queue, push one job per chunk rather than per row.
29. How do enums and readonly properties show up in Laravel code?
Backed enums (PHP 8.1) replace string constants for statuses and types, and Eloquent casts columns to them: 'status' => OrderStatus::class. Route model binding and validation (Rule::enum()) understand them too.
Readonly properties and readonly classes (PHP 8.2) suit value objects and data transfer objects, where a promoted constructor property should never change after creation. They pair well with PHP 8.5's clone() with new values, covered below.
What Changed Recently
30. Where did the HTTP kernel and console kernel go in Laravel 11?
They were removed from new apps, and their settings moved into bootstrap/app.php. The Laravel 11 release notes call it a streamlined application structure.
return Application::configure(basePath: dirname(__DIR__))
->withRouting(web: __DIR__.'/../routes/web.php', health: '/up')
->withMiddleware(function (Middleware $middleware) {
$middleware->web(append: [EnsureUserIsSubscribed::class]);
})
->withExceptions(function (Exceptions $exceptions) {})
->create();
Schedules moved to routes/console.php through the Schedule facade. Commands in app/Console/Commands register automatically. Existing apps did not have to adopt the new layout, so a candidate may meet both in one company.
31. What does Laravel 13 require, and what did it add?
Laravel 13 requires PHP 8.3 or later. The release notes describe it as a small upgrade for most apps.

The additions a candidate should recognize are the Laravel AI SDK (one API for text, agents, embeddings, images and audio), JSON:API resources, vector similarity queries such as whereVectorSimilarTo() on PostgreSQL with pgvector, Queue::route() to set a job's connection and queue in one place, and Cache::touch() to extend a cache item's TTL.
Attributes such as #[Middleware] and #[Tries] now cover more of the framework.
32. How does CSRF protection work in Laravel 13?
The PreventRequestForgery middleware first checks the browser's Sec-Fetch-Site header, which says whether a request came from the same origin. If that check does not pass, it falls back to the classic CSRF token.
The CSRF docs also describe an origin-only mode, preventRequestForgery(originOnly: true), which drops the token fallback. Forms still need @csrf unless you choose that mode.
33. What are property hooks and asymmetric visibility in PHP 8.4?
Property hooks attach get and set logic to a property itself, so you no longer need getter and setter methods to transform a value. Asymmetric visibility lets a property be public to read but private to write.
class Money
{
public private(set) int $cents = 0;
public string $currency {
set(string $value) { $this->currency = strtoupper($value); }
}
}
The PHP 8.4 announcement also lists array_find(), array_any(), lazy objects, and calling a method on new Foo() without extra parentheses. Laravel 11, 12 and 13 all support PHP 8.4.
34. What do the pipe operator and clone with do in PHP 8.5?
The pipe operator |> passes a value through a series of callables from left to right. clone($object, ['prop' => $value]) copies an object and changes properties in one step, which makes "with-er" methods on readonly classes one line long.
$slug = $title
|> trim(...)
|> strtolower(...);
return clone($this, ['alpha' => $alpha]);
Per the PHP 8.5 announcement, the release also added a built-in URI extension, the #[\NoDiscard] attribute, and array_first() and array_last(). Laravel 12 and 13 support PHP 8.5; Laravel 11 does not.
35. Which starter kit does a new Laravel app use now?
One of the kits introduced with Laravel 12: React, Svelte, Vue or Livewire. The Laravel 12 release notes state that Breeze and Jetstream "will no longer receive additional updates".
The React, Svelte and Vue kits use Inertia 2, TypeScript, shadcn/ui and Tailwind. The Livewire kit uses Flux UI and Volt. Each kit also has a WorkOS AuthKit variant with social login, passkeys and SSO.
A candidate still maintaining a Breeze app is fine; one who would start a new project on it has not kept up.
Signs of a Strong Answer
- They turn on
preventLazyLoading()outside production without being asked, and read query logs before adding caches. - They mention
afterCommitwhen a job is dispatched inside a transaction. - They know workers and Octane keep code in memory, so they talk about
queue:restartand stale singletons. - They pass
$request->validated()to models and can explain why$request->all()is risky. - They describe the Laravel 11 structure (
bootstrap/app.php, auto-discovered events and commands) rather than the old kernel files. - They say which PHP version their last app ran and what the upgrade to Laravel 13 needed.
Hiring Laravel Developers
Laravel work tends to mix PHP, SQL and queue operations, so screen for all three. Second Talent matches companies with pre-vetted PHP and Laravel developers from Asia, screened with questions like these.
See what they cost on our Laravel developer cost page.
Tell us the stack and we send a shortlist within 24 hours. Start hiring, or use our PHP coding challenges and MySQL interview questions for the practical round.






