eloquent-best-practices — Claude Code skill: what it does & setup
Provides guidelines for Laravel Eloquent ORM, from eager loading relationships to mass assignment guards. Useful for keeping queries fast and preventing N+1 problems.
npx skills add iSerter/laravel-claude-agents --skill eloquent-best-practices -a claude-codeWhat eloquent-best-practices does
The skill provides your coding agent with an Eloquent ORM reference guide. It directs the model to eager load relationships using with(), call withCount() instead of running counting queries inside loops, and retrieve only required columns via select(). This stops N+1 query bottlenecks before code reaches production.
It covers model structure, attributes, and migrations. The guidelines enforce explicit return types such as BelongsTo and HasMany, cast definitions via $casts, and foreign key indexing. For large datasets, it prioritizes chunk() or lazy() collections over loading entire tables into memory.
Setting protected $guarded = [] is explicitly flagged as unsafe due to mass assignment risks. The guide works best when paired with Model::preventLazyLoading() enabled in your local AppServiceProvider.
What it helps with
- prevent N+1 query issues using eager loading
- process large datasets with chunk and lazy collections
- guard Laravel models against mass assignment vulnerabilities
- enforce return types on Eloquent relationship methods
Example prompts for the agent
- Review my Laravel models and queries for potential N+1 query issues.
- Create a Post model with typed relations, attribute casts, and fillable fields.
- Refactor this bulk update loop into a direct database-level query.
How to install eloquent-best-practices
1Skills CLI (Vercel)
npx skills add iSerter/laravel-claude-agents --skill eloquent-best-practices -a claude-code2Manually: put the files in place
~/.claude/skills/eloquent-best-practices/SKILL.mdCopy the whole skill folder; for one project use .claude/skills/eloquent-best-practices/
1Skills CLI (Vercel)
npx skills add iSerter/laravel-claude-agents --skill eloquent-best-practices -a codex2Manually: put the files in place
.agents/skills/eloquent-best-practices/SKILL.mdFor all projects use ~/.agents/skills/
1Skills CLI (Vercel)
npx skills add iSerter/laravel-claude-agents --skill eloquent-best-practices -a cursor2Manually: put the files in place
.cursor/skills/eloquent-best-practices/SKILL.mdCursor also reads .agents/skills/ and .claude/skills/
1GitHub CLI
gh skill install iSerter/laravel-claude-agents eloquent-best-practices2Manually: put the files in place
.github/skills/eloquent-best-practices/SKILL.md1Skills CLI (Vercel)
npx skills add iSerter/laravel-claude-agents --skill eloquent-best-practices -a gemini-cli2Platform CLI
gemini skills install https://github.com/iSerter/laravel-claude-agents --path skills/eloquent-best-practicesManually: put the files in place
.devin/skills/eloquent-best-practices/SKILL.mdThe legacy .windsurf/skills/ path still works
Skills CLI (Vercel)
npx skills add iSerter/laravel-claude-agents --skill eloquent-best-practices -a opencodeClaude.ai
Zip the folder and upload it in Settings → Capabilities → Skills
Step by step, with commands for each platform: How to install skills in Claude Code: five ways
Questions about eloquent-best-practices
How do I install eloquent-best-practices in Claude Code?
Run npx skills add iSerter/laravel-claude-agents --skill eloquent-best-practices -a claude-code in your terminal. You can also place the skill file directly at ~/.claude/skills/eloquent-best-practices/SKILL.md.
What does the eloquent-best-practices skill do?
It gives your assistant a checklist of best practices for writing performant Laravel Eloquent queries, configuring model guards, and indexing database migrations.
How does it address lazy loading during development?
It recommends adding Model::preventLazyLoading(!app()->isProduction()) inside the boot method of AppServiceProvider.
Source text
SKILL.md · MIT
---
name: eloquent-best-practices
description: Best practices for Laravel Eloquent ORM including query optimization, relationship management, and avoiding common pitfalls like N+1 queries.
---
# Eloquent Best Practices
## Query Optimization
### Always Eager Load Relationships
```php
// ❌ N+1 Query Problem
$posts = Post::all();
foreach ($posts as $post) {
echo $post->user->name; // N additional queries
}
// ✅ Eager Loading
$posts = Post::with('user')->get();
foreach ($posts as $post) {
echo $post->user->name; // No additional queries
}
```
### Select Only Needed Columns
```php
// ❌ Fetches all columns
$users = User::all();
// ✅ Only needed columns
$users = User::select(['id', 'name', 'email'])->get();
// ✅ With relationships
$posts = Post::with(['user:id,name'])->select(['id', 'title', 'user_id'])->get();
```
### Use Query Scopes
```php
// ✅ Define reusable query logic
class Post extends Model
{
public function scopePublished($query)
{
return $query->where('status', 'published')
->whereNotNull('published_at');
}
public function scopePopular($query, $threshold = 100)
{
return $query->where('views', '>', $threshold);
}
}
// Usage
$posts = Post::published()->popular()->get();
```
## Relationship Best Practices
### Define Return Types
```php
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
class Post extends Model
{
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
public function comments(): HasMany
{
return $this->hasMany(Comment::class);
}
}
```
### Use withCount for Counts
```php
// ❌ Triggers additional queries
foreach ($posts as $post) {
echo $post->comments()->count();
}
// ✅ Load counts efficiently
$posts = Post::withCount('comments')->get();
foreach ($posts as $post) {
echo $post->comments_count;
}
```
## Mass Assignment Protection
```php
class Post extends Model
{
// ✅ Whitelist fillable attributes
protected $fillable = ['title', 'content', 'status'];
// Or blacklist guarded attributes
protected $guarded = ['id', 'user_id'];
// ❌ Never do this
// protected $guarded = [];
}
```
## Use Casts for Type Safety
```php
class Post extends Model
{
protected $casts = [
'published_at' => 'datetime',
'metadata' => 'array',
'is_featured' => 'boolean',
'views' => 'integer',
];
}
```
## Chunking for Large Datasets
```php
// ✅ Process in chunks to save memory
Post::chunk(200, function ($posts) {
foreach ($posts as $post) {
// Process each post
}
});
// ✅ Or use lazy collections
Post::lazy()->each(function ($post) {
// Process one at a time
});
```
## Database-Level Operations
```php
// ❌ Slow - loads into memory first
$posts = Post::where('status', 'draft')->get();
foreach ($posts as $post) {
$post->update(['status' => 'archived']);
}
// ✅ Fast - single query
Post::where('status', 'draft')->update(['status' => 'archived']);
// ✅ Increment/decrement
Post::where('id', $id)->increment('views');
```
## Use Model Events Wisely
```php
class Post extends Model
{
protected static function booted()
{
static::creating(function ($post) {
$post->slug = Str::slug($post->title);
});
static::deleting(function ($post) {
$post->comments()->delete();
});
}
}
```
## Common Pitfalls to Avoid
### Don't Query in Loops
```php
// ❌ Bad
foreach ($userIds as $id) {
$user = User::find($id);
}
// ✅ Good
$users = User::whereIn('id', $userIds)->get();
```
### Don't Forget Indexes
```php
// Migration
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->foreignId('user_id')->constrained()->index();
$table->string('slug')->unique();
$table->string('status')->index();
$table->timestamp('published_at')->nullable()->index();
// Composite index for common queries
$table->index(['status', 'published_at']);
});
```
### Prevent Lazy Loading in Development
```php
// In AppServiceProvider boot method
Model::preventLazyLoading(!app()->isProduction());
```
## Checklist
- [ ] Relationships eagerly loaded where needed
- [ ] Only selecting required columns
- [ ] Using query scopes for reusability
- [ ] Mass assignment protection configured
- [ ] Appropriate casts defined
- [ ] Indexes on foreign keys and query columns
- [ ] Using database-level operations when possible
- [ ] Chunking for large datasets
- [ ] Model events used appropriately
- [ ] Lazy loading prevented in development
© iSerter · MIT · iSerter/laravel-claude-agents