Apply this skill whenever writing, reviewing, or refactoring Laravel PHP code. This includes creating or modifying controllers, models, migrations, form requests, policies, jobs, scheduled commands, service classes, and Eloquent queries. Triggers for N+1 and query performance issues, caching strategies, authorization and security patterns, validation, error handling, queue and job configuration, route definitions, and architectural decisions. Also use for Laravel code reviews and refactoring existing Laravel code to follow best practices. Covers any task involving Laravel backend PHP code patterns.
Best practices for Laravel, prioritized by impact. Each rule teaches what to do and why. For exact API syntax, verify with search-docs.
Before applying any rule, check what the application already does. Laravel offers multiple valid approaches — the best choice is the one the codebase already uses, even if another pattern would be theoretically better. Inconsistency is worse than a suboptimal pattern.
Check sibling files, related controllers, models, or tests for established patterns. If one exists, follow it — don't introduce a second way. These rules are defaults for when no pattern exists yet, not overrides.
rules/db-performance.mdwith() to prevent N+1 queriesModel::preventLazyLoading() in developmentSELECT *chunk() / chunkById() for large datasetsWHERE, ORDER BY, JOINwithCount() instead of loading relations to countcursor() for memory-efficient read-only iterationrules/advanced-queries.mdaddSelect() subqueries over eager-loading entire has-many for a single valuebelongsToCASE WHEN in selectRaw) over multiple count queriessetRelation() to prevent circular N+1 querieswhereIn + pluck() over whereHas for better index usageorderBy column orderorderBy for has-many sorting (avoid joins)rules/security.md$fillable or $guarded on every model, authorize every action via policies or gates{{ }} for output escaping, @csrf on all POST/PUT/DELETE forms, throttle on auth and API routes.env, use config() for secrets, encrypted cast for sensitive DB fieldsrules/caching.mdCache::remember() over manual get/putCache::flexible() for stale-while-revalidate on high-traffic dataCache::memo() to avoid redundant cache hits within a requestCache::add() for atomic conditional writesonce() to memoize per-request or per-object lifetimeCache::lock() / lockForUpdate() for race conditionsrules/eloquent.mdcasts() methodwhereBelongsTo($model) for cleaner queries(new Model)->getTable() or Eloquent queriesrules/validation.md['required', 'email'] for new code; follow existing convention$request->validated() only — never $request->all()Rule::when() for conditional validationafter() instead of withValidator()rules/config.mdenv() only inside config filesApp::environment() or app()->isProduction()rules/testing.mdLazilyRefreshDatabase over RefreshDatabase for speedassertModelExists() over raw assertDatabaseHas()Event::fake(), Exceptions::fake(), etc.) — but always after factory setup, not beforerecycle() to share relationship instances across factoriesrules/queue-jobs.mdretry_after must exceed job timeout; use exponential backoff [1, 5, 10]ShouldBeUnique to prevent duplicates; ShouldBeUniqueUntilProcessing for early lock releasefailed(); with retryUntil(), set $tries = 0RateLimited middleware for external API calls; Bus::batch() for related jobsrules/routing.mdRoute::resource() or apiResource()rules/http-client.mdtimeout and connectTimeout on every requestretry() with exponential backoff for external APIsthrow()Http::pool() for concurrent independent requestsHttp::fake() and preventStrayRequests() in testsrules/events-notifications.md, rules/mail.mdevent:cache in productionShouldDispatchAfterCommit / afterCommit() inside transactionsShouldQueueHasLocalePreference on notifiable modelsassertQueued() not assertSent() for queued mailablesrules/error-handling.mdreport()/render() on exception classes or in bootstrap/app.php — follow existing patternShouldntReport for exceptions that should never logdontReportDuplicates() for multi-catch scenarioscontext() on exception classesrules/scheduling.mdwithoutOverlapping() on variable-duration tasksonOneServer() on multi-server deploymentsrunInBackground() for concurrent long tasksenvironments() to restrict to appropriate environmentstakeUntilTimeout() for time-bounded processingrules/architecture.mdapp() helperORDER BY id DESC or created_at DESC; mb_* for UTF-8 safetydefer() for post-response work; Context for request-scoped data; Concurrency::run() for parallel executionrules/migrations.mdphp artisan make:migrationconstrained() for foreign keys$attributesdown() by default; forward-fix migrations for intentionally irreversible changesrules/collections.mdcursor() vs. lazy() — choose based on relationship needslazyById() when updating records while iteratingtoQuery() for bulk operations on collectionsrules/blade-views.md$attributes->merge() in component templates@include; @pushOnce for per-component scripts@aware for deeply nested component propsrules/style.mdStr, Arr, Number, Uri, Str::of(), $request->string()) over raw PHP functionsAlways use a sub-agent to read rule files and explore this skill's content.
search-docs for the installed Laravel version