home / skills / hoangnguyen0403 / agent-skills-standard / eloquent

eloquent skill

/skills/laravel/eloquent

This skill optimizes Laravel Eloquent usage for performance and reuse by guiding eager loading, scopes, and safe mass assignment patterns.

npx playbooks add skill hoangnguyen0403/agent-skills-standard --skill eloquent

Review the files below or copy the command above to add this skill to your agents.

Files (2)
SKILL.md
1.3 KB
---
name: Laravel Eloquent
description: Advanced Eloquent ORM patterns for performance and query reuse.
metadata:
  labels: [laravel, eloquent, orm, database]
  triggers:
    files: ['app/Models/**/*.php']
    keywords: [scope, with, eager, chunk, model]
---

# Laravel Eloquent

## **Priority: P0 (CRITICAL)**

## Structure

```text
app/
└── Models/
    ├── {Model}.php
    └── Scopes/         # Advanced global scopes
```

## Implementation Guidelines

- **N+1 Prevention**: Always use `with()` or `$with` for relationships.
- **Eager Loading**: Set strict loading via `Eloquent::preventLazyLoading()`.
- **Reusable Scopes**: Define `scopeName` methods for common query filters.
- **Mass Assignment**: Define `$fillable` and use `$request->validated()`.
- **Performance**: Use `chunk()`, `lazy()`, or `cursor()` for large tasks.
- **Casting**: Use `$casts` for dates, JSON, and custom types.

## Anti-Patterns

- **N+1 Queries**: **No lazy loading**: Never query relationships in loops.
- **Fat Models**: **No business logic**: Models are for data access only.
- **Magic Queries**: **No raw SQL**: Use Query Builder or Eloquent.
- **Select \***: **No excessive data**: Select only required columns.

## References

- [Eloquent Performance Guide](references/implementation.md)

Overview

This skill codifies advanced Laravel Eloquent patterns focused on performance, maintainability, and reusable queries. It provides concrete conventions for model structure, eager loading, scopes, casting, and batch processing to avoid common pitfalls. The goal is predictable, efficient data access across teams and agents.

How this skill works

The skill enforces model layout with a Models folder and optional Scopes subfolder, and encourages defining scopeX methods for reusable filters. It prescribes eager-loading strategies (with and $with), prevents lazy loading during development, and recommends chunk/lazy/cursor for large data tasks. It also standardizes mass-assignment via $fillable and validated requests, plus $casts for type safety.

When to use it

  • Building or refactoring data-access layers in Laravel applications.
  • Preventing N+1 query problems and enforcing eager loading.
  • Implementing shared query logic across controllers or services.
  • Processing large datasets without exhausting memory.
  • Standardizing model behavior for team projects or automation agents.

Best practices

  • Always define relationships with with() or set $with to prevent lazy loads.
  • Enable Eloquent::preventLazyLoading() in non-production environments to catch N+1s early.
  • Encapsulate common filters as local scopes (scopeActive, scopePublished) for reuse.
  • Declare $fillable and use $request->validated() to avoid mass-assignment risks.
  • Use chunk(), lazy(), or cursor() for bulk operations to keep memory usage stable.
  • Cast attributes with $casts for dates, JSON, and custom types to ensure consistent types.

Example use cases

  • Create a scopeRecentPublished() on Post to reuse in APIs, admin panels, and exports.
  • Run a nightly email job using cursor() to stream millions of users without loading all rows.
  • Refactor controllers that trigger N+1 queries by adding with() to the base queries.
  • Enforce data contracts by using $fillable combined with form request validated() output.
  • Add advanced global scopes in Models/Scopes to apply tenant or soft-delete filters consistently.

FAQ

How do I stop N+1 queries during development?

Enable Eloquent::preventLazyLoading() in local and testing environments and use with() or $with to declare relationships.

When should I use chunk() vs cursor()?

Use chunk() when you need batches and can process sets in memory; use cursor() or lazy() to stream rows one by one for minimal memory use.