agentsclimarketplace

Laravel eloquent performance

Skill kwhorne/elyra-skills/skills/laravel-eloquent-performance

Find and fix Eloquent performance problems - N+1 queries, eager loading strategy, chunking, indexes, and query review for Laravel apps. Use when a Laravel page or job is slow, when reviewing Eloquent code for query efficiency, when the user mentions N+1 problems, or before shipping list views and reports that touch large tables.From its SKILL.md

Install
npx -y skills add kwhorne/elyra-skills --skill laravel-eloquent-performance

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its file declares

Copied from the file, not written here

The file declares its own license as MIT. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.

SKILL.md

4.5 KB, ~1.0k tokens by cl100k_base, as published. Nobody here has run it

Laravel Eloquent Performance

Eloquent makes queries invisible — which is how one Blade loop quietly becomes 300 of them. Make queries visible first, then fix the worst offender, then prevent recurrence.

When to use

  • A Laravel page, endpoint, or job is slow
  • Reviewing code that loops over models or renders collections
  • "We have an N+1 problem" / preparing list views, exports, dashboards
  • Before shipping anything that touches large tables

Principles

  • Measure before touching. Count queries and duration; don't guess from code shape.
  • The database does sets; PHP does rows. Filtering, counting, and aggregating in a ->filter()/->count() after ->get() is the cardinal sin.
  • Load what the view needs, nothing more. Eager load relations the page renders; select the columns it shows.
  • Prevention beats heroics. One strict-mode line catches future N+1s in development forever.

Process

1. Make queries visible

// AppServiceProvider::boot() — development
Model::shouldBeStrict(! app()->isProduction());   // throws on lazy loading, silent attribute access
DB::listen(fn ($q) => logger()->debug($q->sql, ['ms' => $q->time]));

Or use Debugbar/Telescope/->dd() on the query log for the specific request. Record: query count + total ms as the baseline.

2. Fix N+1 (the usual suspect)

// Symptom: query per row in a loop
$posts = Post::with(['author', 'comments.user'])->get();    // eager load
$posts = Post::withCount('comments')->get();                 // counts without loading
$query->withAvg('reviews', 'rating');                        // aggregates likewise
  • Nested relations: with('comments.user'), constrained: with(['comments' => fn ($q) => $q->latest()->limit(5)])
  • In Blade components rendered per-row: the N+1 hides in the component — eager load in the parent query

3. Stop over-fetching

  • ->select(['id', 'title', 'author_id']) — include FKs needed by with()
  • Big text/blob columns excluded from list queries
  • exists() not count() > 0; value('col') not first()->col

4. Move work to the database

PHP smellDatabase fix
->get()->filter(...)->where(...)
->get()->count()->count()
->get()->sum('x')->sum('x')
->get()->groupBy(...)->groupBy() + aggregate, or a dedicated query

5. Handle large datasets

  • Iteration: chunkById() (not chunk() when mutating rows) or lazyById() / cursor()
  • Exports/jobs: never all() on an unbounded table
  • Pagination: paginate() for UI; cursorPaginate() for infinite scroll / large offsets

6. Check indexes

php artisan db:table <table>            # see existing indexes
  • Every column in where/orderBy/joins on big tables: candidate
  • Composite index order: equality columns first, then range/sort
  • Verify with DB::select('EXPLAIN ...') — look for full table scans

7. Re-measure and lock in

  • Compare query count + ms against baseline; report both
  • Keep Model::shouldBeStrict() in non-production permanently
  • Add a CI-friendly assertion where it matters: e.g. test that a page renders in ≤ N queries

Output format

## Eloquent performance: <page/endpoint/job>

**Baseline:** N queries / X ms → **After:** M queries / Y ms

### Fixes
1. <file:line> — <problem> → <fix>

### Indexes added/proposed
- <table>.<cols> — for <query>

### Prevention
- strict mode: on | query-count test: added | …

Anti-patterns

  • ❌ Sprinkling with() everywhere "just in case" — eager loading unrendered relations is its own waste
  • ❌ Caching as the first response to a slow query instead of fixing the query
  • chunk() while updating the column you chunk by (rows get skipped — use chunkById())
  • ❌ Fixing the N+1 in the controller while the Blade component re-introduces it
  • ❌ Adding indexes without checking they're used (EXPLAIN)
  • ❌ Declaring victory without before/after numbers

What ships with it

Read from the repository

Just SKILL.md. No reference files, no scripts.

Gives 0 of the 12 instructions most performance cost skills give in ~1.0k tokens

Counted across 803 of the 1,058 authors here whose files we hold, read 2026-08-07

  • Keep skill files under 500 lines or tokensin 82 of 803, across 16 files
  • Use imperative form in instructionsin 80 of 803, across 9 files
  • Draft assertions while test runs are in progressin 75 of 803, across 9 files
  • Create two to three realistic test promptsin 74 of 803, across 9 files
  • Write skill descriptions to be pushyin 72 of 803, across 7 files
  • Save test cases to evals JSONin 72 of 803, across 6 files
  • Ask questions about edge cases and input formatsin 72 of 803, across 7 files
  • Save timing data immediately when runs completein 70 of 803, across 5 files
  • Include all trigger conditions in the skill descriptionin 69 of 803, across 3 files
  • Launch all test runs in a single turn or simultaneouslyin 69 of 803, across 3 files
  • Capture intent before writing a skillin 67 of 803, across 1 file
  • Import directly instead of barrel filesin 52 of 803, across 15 files

Said here and by no other author read

  • measure queries and duration before fixing
  • enable Eloquent strict mode in non-production
  • use database aggregates instead of PHP collection methods
  • verify added indexes are used by EXPLAIN
  • add CI tests asserting maximum query counts

Grouped from the skills themselves: near-identical wordings counted once, and counted by distinct author, so one author publishing three of these counts once. Length counted with cl100k_base; the agent that loads this file may tokenize it differently.

Keep looking

Skills are one crate of 326,871. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.