lc-find-n-plus-one
Detect N+1 query problems in Blade views, Livewire components, and controllers.
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
メニュー
Detect N+1 query problems in Blade views, Livewire components, and controllers.
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
SOC 職業分類に基づく
Create a Larascraper scraper (v2 or v3) for a target website, chaining browser actions (click, type, wait, scroll), conditional flow (when/repeatUntil), captcha solving, and file/PDF downloads. Detects the installed major and generates the matching style.
Add or edit a Laracrate file collection in config/laracrate.php with the correct anatomy (disk, access, types, variants, previews, extract/embed, flags, per-model scoping).
Runtime-verified Laravel inspection using the Laravel Boost MCP server (Tinker, Database Query/Schema, Last Error) instead of static grep. Falls back to Docker/Tinker if Boost is not installed.
Scaffold spatie/laravel-permission setup - add the HasRoles trait to a model and generate a roles & permissions seeder.
Audit spatie/laravel-permission usage - permissions used in code but undefined, defined but unused, unprotected routes, guard mismatches, and cache pitfalls.
Extract business logic from a controller or Livewire component method into a Laractions Action class.
| name | lc:find-n-plus-one |
| description | Detect N+1 query problems in Blade views, Livewire components, and controllers. |
| argument-hint | [analyze | fix | fix --dry-run | file-path | fix file-path] |
| user-invocable | true |
| allowed-tools | Read Grep Bash Edit Write Glob |
Statically analyze Blade views, Livewire/Volt components, and controllers to detect N+1 query problems where relationships are accessed inside loops without eager loading.
| Subcommand | Description |
|---|---|
| (no argument) | Scan the entire project for N+1 problems. Read-only report. |
fix | Scan and auto-add with() eager loading to queries. Asks for confirmation before each change. |
fix --dry-run | Show what with() calls would be added without changing anything. |
[file-path] | Analyze a specific file and trace its data sources. Read-only. |
fix [file-path] | Fix N+1 issues in a specific file, with confirmation. |
An N+1 query problem occurs when code accesses a relationship on a model inside a loop, causing one query per iteration instead of a single eager-loaded query. For example:
// BAD: N+1 -- runs 1 query for properties + N queries for office
@foreach($properties as $property)
{{ $property->office->name }} // Each iteration hits the database
@endforeach
// GOOD: Eager loaded -- runs 2 queries total
$properties = Property::with('office')->get();
@foreach($properties as $property)
{{ $property->office->name }} // No additional query
@endforeach
[file-path] argument is provided, analyze only that file and trace its data sources.Glob to find:
resources/views/**/*.blade.php (Blade views)app/Http/Controllers/**/*.php (Controllers)app/Livewire/**/*.php (Livewire class components, if any exist)For each Blade file, use Read to load the content and identify:
@foreach, @forelse, @for, @while, and nested loops.$variable->relationship where relationship is a known model relationship$variable->relationship->property$variable->relationship()->...$variable->relationship->count()$variable->loadCount('relationship') inside loops (should be done before the loop)$property->office->organization->name -- multiple levels of lazy loading.To determine if a property access is a relationship:
$appends array (appended attributes are not relationships even if they share a name).For each loop variable, trace where the data comes from:
mount() or computed propertiesrender() or with() methodswith() or load() is called on the queryGrep to find which controller renders this view (return view('view.name', ...))with(), load(), or loadMissing() callsFor each relationship accessed inside a loop, determine:
with('relationship') is called on the query that builds the collection.$with on the model? Some models define protected $with = ['relationship'] for automatic eager loading.loadMissing() or whenLoaded() patterns.Flag as N+1 only if the relationship is NOT eager-loaded by any of these mechanisms.
Beyond simple loop access, check for:
Accessor N+1: Model accessors that access relationships, called from within loops.
// In Model
public function getFullAddressAttribute() {
return $this->location->name . ', ' . $this->location->province->name; // N+1!
}
// In Blade
@foreach($properties as $property)
{{ $property->full_address }} // Triggers N+1 via accessor
@endforeach
Relationship count N+1: Using $model->relationship->count() instead of withCount().
@foreach($properties as $property)
{{ $property->images->count() }} // Loads all images just to count
@endforeach
Conditional relationship access: Relationships accessed inside @if blocks within loops.
@foreach($properties as $property)
@if($property->showcase) // N+1 even though it's conditional
{{ $property->showcase->name }}
@endif
@endforeach
Component rendering N+1: Livewire/Blade components rendered inside loops that internally access relationships.
For each N+1 problem found, report:
N+1 QUERY DETECTED
===================
File: /absolute/path/to/resources/views/livewire/properties/index.blade.php
Line: 45
Loop: @foreach($properties as $property)
Access: $property->office->name
Data Source: Livewire computed property in same file (line 12)
Query: Property::where('organization_id', $this->organizationId)->paginate(20)
Problem: 'office' relationship is not eager-loaded. This will execute 1 additional
query per property in the collection (20 queries for a page of 20).
Fix: Add ->with('office') to the query:
Property::where('organization_id', $this->organizationId)
->with('office')
->paginate(20);
End with a summary table:
N+1 ANALYSIS SUMMARY
======================
Files scanned: 85
Loops analyzed: 142
Relationship accesses: 234
N+1 problems found: 12
By severity:
High (in paginated/large collections): 4
Medium (in moderate collections): 5
Low (in small/bounded collections): 3
Top offenders:
resources/views/livewire/properties/index.blade.php - 4 issues
resources/views/livewire/clients/show.blade.php - 3 issues
resources/views/livewire/operations/table.blade.php - 2 issues
fix or fix [file-path])For each N+1 problem detected, automatically add the missing with() calls:
with() call, or add a new ->with('relationship') clause.->count() access with withCount() on the query.fix --dry-run)Show exactly what query modifications would be made, with before/after diffs, without writing any changes.
->take(5), enum values, etc.).morphTo) are harder to trace -- note these as "needs manual review" if uncertain.$with model property provides automatic eager loading and should be checked before flagging.