{"id":"e8b5cab2-b24f-47bc-8399-a0eaee656049","shortId":"jznUw6","kind":"skill","title":"laravel-best-practices","tagline":"Laravel 13 conventions and best practices. Use when creating controllers, models, migrations, validation, services, or structuring Laravel applications. Triggers on tasks involving Laravel architecture, Eloquent, database, API development, or PHP patterns.","description":"# Laravel 13 Best Practices\n\nComprehensive best practices guide for Laravel 13 applications. Contains 31 rules across 7 categories for building scalable, maintainable Laravel applications.\n\n## When to Apply\n\nReference these guidelines when:\n- Creating controllers, models, and services\n- Writing migrations and database queries\n- Implementing validation and form requests\n- Building APIs with Laravel\n- Structuring Laravel applications\n\n## Rule Categories by Priority\n\n| Priority | Category | Impact | Prefix |\n|----------|----------|--------|--------|\n| 1 | Architecture & Structure | CRITICAL | `arch-` |\n| 2 | Eloquent & Database | CRITICAL | `eloquent-` |\n| 3 | Controllers & Routing | HIGH | `controller-`, `ctrl-` |\n| 4 | Validation & Requests | HIGH | `validation-`, `valid-` |\n| 5 | Security | HIGH | `sec-` |\n| 6 | Performance | MEDIUM | `perf-` |\n| 7 | API Design | MEDIUM | `api-` |\n\n## Quick Reference\n\n### 1. Architecture & Structure (CRITICAL)\n\n- `arch-service-classes` - Extract business logic to services\n- `arch-action-classes` - Single-purpose action classes\n- `arch-repository-pattern` - When to use repositories\n- `arch-dto-pattern` - Data transfer objects\n- `arch-value-objects` - Encapsulate domain concepts\n- `arch-event-driven` - Decouple with events and listeners\n- `arch-feature-folders` - Organize by domain/feature\n- `arch-queue-routing` - Centralized job queue routing (Laravel 13+)\n\n### 2. Eloquent & Database (CRITICAL)\n\n- `eloquent-eager-loading` - Prevent N+1 queries\n- `eloquent-chunking` - Process large datasets\n- `eloquent-query-scopes` - Reusable query logic\n- `eloquent-model-events` - Use observers for side effects\n- `eloquent-relationships` - Define relationships properly\n- `eloquent-casts` - Automatic attribute casting\n- `eloquent-accessors-mutators` - Transform attributes\n- `eloquent-soft-deletes` - Safe deletion with recovery\n- `eloquent-pruning` - Automatic cleanup of old records\n- `eloquent-vector-search` - Semantic search with pgvector (Laravel 13+)\n\n### 3. Controllers & Routing (HIGH)\n\n- `controller-resource-controllers` - Use resource controllers\n- `controller-single-action` - Single action invokable controllers\n- `controller-resource-methods` - RESTful resource methods\n- `controller-form-requests` - Use form requests\n- `controller-api-resources` - Transform API responses\n- `controller-middleware` - Apply middleware properly\n- `controller-dependency-injection` - Inject dependencies\n\n### 4. Validation & Requests (HIGH)\n\n- `validation-form-requests` - Use form request classes\n- `validation-custom-rules` - Create custom rules\n- `validation-conditional-rules` - Conditional validation\n- `validation-array-validation` - Validate nested arrays\n- `validation-after-hooks` - Complex validation logic\n\n### 5. Security (HIGH)\n\n- `sec-mass-assignment` - Protect against mass assignment\n\n### 6. Performance (MEDIUM)\n\nNo rule files exist yet for this category.\n\n### 7. API Design (MEDIUM)\n\nNo rule files exist yet for this category.\n\n## Essential Patterns\n\n### Controller with Form Request\n\n```php\n<?php\n\nnamespace App\\Http\\Controllers;\n\nuse App\\Http\\Requests\\StorePostRequest;\nuse App\\Http\\Requests\\UpdatePostRequest;\nuse App\\Models\\Post;\nuse Illuminate\\Http\\RedirectResponse;\n\nclass PostController extends Controller\n{\n    public function store(StorePostRequest $request): RedirectResponse\n    {\n        // Validation happens automatically\n        $validated = $request->validated();\n\n        $post = Post::create($validated);\n\n        return redirect()\n            ->route('posts.show', $post)\n            ->with('success', 'Post created successfully.');\n    }\n\n    public function update(UpdatePostRequest $request, Post $post): RedirectResponse\n    {\n        $post->update($request->validated());\n\n        return redirect()\n            ->route('posts.show', $post)\n            ->with('success', 'Post updated successfully.');\n    }\n}\n```\n\n### Form Request Class\n\n```php\n<?php\n\nnamespace App\\Http\\Requests;\n\nuse Illuminate\\Foundation\\Http\\FormRequest;\n\nclass StorePostRequest extends FormRequest\n{\n    public function authorize(): bool\n    {\n        return $this->user()->can('create', Post::class);\n    }\n\n    public function rules(): array\n    {\n        return [\n            'title' => ['required', 'string', 'max:255'],\n            'body' => ['required', 'string', 'min:100'],\n            'category_id' => ['required', 'exists:categories,id'],\n            'tags' => ['nullable', 'array'],\n            'tags.*' => ['exists:tags,id'],\n            'published_at' => ['nullable', 'date', 'after:now'],\n        ];\n    }\n\n    public function messages(): array\n    {\n        return [\n            'body.min' => 'The post body must be at least 100 characters.',\n        ];\n    }\n}\n```\n\n### Service Class Pattern\n\n```php\n<?php\n\nnamespace App\\Services;\n\nuse App\\Models\\User;\nuse App\\Models\\Post;\nuse App\\Events\\PostPublished;\nuse Illuminate\\Support\\Facades\\DB;\n\nclass PostService\n{\n    public function __construct(\n        private readonly NotificationService $notifications,\n    ) {}\n\n    public function publish(Post $post): Post\n    {\n        return DB::transaction(function () use ($post) {\n            $post->update([\n                'published_at' => now(),\n                'status' => 'published',\n            ]);\n\n            event(new PostPublished($post));\n\n            $this->notifications->notifyFollowers($post->author, $post);\n\n            return $post->fresh();\n        });\n    }\n}\n```\n\n### Eloquent Model\n\n```php\n<?php\n\nnamespace App\\Models;\n\nuse Illuminate\\Database\\Eloquent\\Factories\\HasFactory;\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Illuminate\\Database\\Eloquent\\Relations\\BelongsTo;\nuse Illuminate\\Database\\Eloquent\\Relations\\BelongsToMany;\nuse Illuminate\\Database\\Eloquent\\Builder;\n\nclass Post extends Model\n{\n    use HasFactory;\n\n    protected $fillable = [\n        'title',\n        'slug',\n        'body',\n        'category_id',\n        'published_at',\n    ];\n\n    protected $casts = [\n        'published_at' => 'datetime',\n    ];\n\n    // Relationships\n    public function author(): BelongsTo\n    {\n        return $this->belongsTo(User::class, 'user_id');\n    }\n\n    public function category(): BelongsTo\n    {\n        return $this->belongsTo(Category::class);\n    }\n\n    public function tags(): BelongsToMany\n    {\n        return $this->belongsToMany(Tag::class)->withTimestamps();\n    }\n\n    // Scopes\n    public function scopePublished(Builder $query): Builder\n    {\n        return $query->whereNotNull('published_at')\n            ->where('published_at', '<=', now());\n    }\n\n    public function scopeByCategory(Builder $query, int $categoryId): Builder\n    {\n        return $query->where('category_id', $categoryId);\n    }\n\n    // Accessors & Mutators\n    protected function title(): Attribute\n    {\n        return Attribute::make(\n            set: fn (string $value) => ucfirst($value),\n        );\n    }\n}\n```\n\n### Migration Best Practices\n\n```php\n<?php\n\nuse Illuminate\\Database\\Migrations\\Migration;\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Support\\Facades\\Schema;\n\nreturn new class extends Migration\n{\n    public function up(): void\n    {\n        Schema::create('posts', function (Blueprint $table) {\n            $table->id();\n            $table->foreignId('user_id')->constrained()->cascadeOnDelete();\n            $table->foreignId('category_id')->constrained()->cascadeOnDelete();\n            $table->string('title');\n            $table->string('slug')->unique();\n            $table->text('body');\n            $table->timestamp('published_at')->nullable();\n            $table->timestamps();\n\n            // Indexes for common queries\n            $table->index(['user_id', 'published_at']);\n            $table->index('category_id');\n        });\n    }\n\n    public function down(): void\n    {\n        Schema::dropIfExists('posts');\n    }\n};\n```\n\n### Eager Loading\n\n```php\n// N+1 Problem\n$posts = Post::all();\nforeach ($posts as $post) {\n    echo $post->author->name;  // Query per post\n}\n\n// Eager loading — only 3 queries total\n$posts = Post::with(['author', 'category', 'tags'])->get();\nforeach ($posts as $post) {\n    echo $post->author->name;  // No additional queries\n}\n\n// Nested eager loading\n$posts = Post::with([\n    'author.profile',\n    'comments.user',\n    'tags',\n])->get();\n\n// Constrained eager loading\n$posts = Post::with([\n    'comments' => fn ($query) => $query->latest()->limit(5),\n])->get();\n```\n\n## How to Use\n\nRead individual rule files for detailed explanations and code examples:\n\n```\nrules/arch-service-classes.md\nrules/eloquent-eager-loading.md\nrules/validation-form-requests.md\nrules/_sections.md\n```\n\nEach rule file contains:\n- YAML frontmatter with metadata (title, impact, tags)\n- Brief explanation of why it matters\n- Bad Example with explanation\n- Good Example with explanation\n- Laravel 13 and PHP 8.3 specific context and references\n\n## Full Compiled Document\n\nFor the complete guide with all rules expanded: `AGENTS.md`","tags":["laravel","best","practices","agent","skills","asyrafhussin","agent-rules","agent-skills","ai-agents","ai-slop","claude-code","code-quality"],"capabilities":["skill","source-asyrafhussin","skill-laravel-best-practices","topic-agent-rules","topic-agent-skills","topic-ai-agents","topic-ai-slop","topic-claude-code","topic-code-quality","topic-code-review","topic-codex","topic-cursor","topic-laravel","topic-nodejs","topic-react"],"categories":["agent-skills"],"synonyms":[],"warnings":[],"endpointUrl":"https://skills.sh/AsyrafHussin/agent-skills/laravel-best-practices","protocol":"skill","transport":"skills-sh","auth":{"type":"none","details":{"cli":"npx skills add AsyrafHussin/agent-skills","source_repo":"https://github.com/AsyrafHussin/agent-skills","install_from":"skills.sh"}},"qualityScore":"0.469","qualityRationale":"deterministic score 0.47 from registry signals: · indexed on github topic:agent-skills · 39 github stars · SKILL.md body (8,955 chars)","verified":false,"liveness":"unknown","lastLivenessCheck":null,"agentReviews":{"count":0,"score_avg":null,"cost_usd_avg":null,"success_rate":null,"latency_p50_ms":null,"narrative_summary":null,"summary_updated_at":null},"enrichmentModel":"deterministic:skill-github:v1","enrichmentVersion":1,"enrichedAt":"2026-05-18T18:58:24.452Z","embedding":null,"createdAt":"2026-05-16T18:57:14.193Z","updatedAt":"2026-05-18T18:58:24.452Z","lastSeenAt":"2026-05-18T18:58:24.452Z","tsv":"'+1':214,855 '1':97,134 '100':532,565 '13':6,37,46,203,281,962 '2':102,204 '255':527 '3':107,282,874 '31':49 '4':113,334 '5':119,373,917 '6':123,384 '7':52,127,395 '8.3':965 'accessor':252,749 'across':51 'action':149,154,296,298 'addit':893 'agents.md':981 'api':31,83,128,131,317,320,396 'app':416,420,425,430,495,573,576,580,584,638 'appli':62,325 'applic':22,47,59,88 'arch':101,139,148,157,165,172,179,188,195 'arch-action-class':147 'arch-dto-pattern':164 'arch-event-driven':178 'arch-feature-fold':187 'arch-queue-rout':194 'arch-repository-pattern':156 'arch-service-class':138 'arch-value-object':171 'architectur':28,98,135 'array':361,365,521,541,555 'assign':379,383 'attribut':248,255,754,756 'author':509,628,691,866,880,890 'author.profile':901 'automat':247,267,449 'bad':953 'belongsto':656,692,695,703,706 'belongstomani':662,712,715 'best':3,9,38,41,765 'blueprint':778,797 'bodi':528,560,678,822 'body.min':557 'bool':510 'brief':947 'build':55,82 'builder':667,723,725,738,742 'busi':143 'cascadeondelet':806,812 'cast':246,249,684 'categori':53,90,94,394,406,533,537,679,702,707,746,809,842,881 'categoryid':741,748 'central':198 'charact':566 'chunk':218 'class':141,150,155,345,437,491,503,517,568,592,668,697,708,717,786 'cleanup':268 'code':930 'comment':911 'comments.user':902 'common':832 'compil':971 'complet':975 'complex':370 'comprehens':40 'concept':177 'condit':355,357 'constrain':805,811,905 'construct':596 'contain':48,939 'context':967 'control':14,68,108,111,283,287,289,292,294,300,302,309,316,323,329,409,418,440 'controller-api-resourc':315 'controller-dependency-inject':328 'controller-form-request':308 'controller-middlewar':322 'controller-resource-control':286 'controller-resource-method':301 'controller-single-act':293 'convent':7 'creat':13,67,350,455,465,515,794 'critic':100,105,137,207 'ctrl':112 'custom':348,351 'data':168 'databas':30,75,104,206,642,648,653,659,665,771,776 'dataset':221 'date':549 'datetim':687 'db':591,608 'decoupl':182 'defin':241 'delet':259,261 'depend':330,333 'design':129,397 'detail':927 'develop':32 'document':972 'domain':176 'domain/feature':193 'driven':181 'dropifexist':849 'dto':166 'eager':210,851,871,896,906 'echo':864,888 'effect':237 'eloqu':29,103,106,205,209,217,223,230,239,245,251,257,265,273,633,643,649,654,660,666 'eloquent-accessors-mut':250 'eloquent-cast':244 'eloquent-chunk':216 'eloquent-eager-load':208 'eloquent-model-ev':229 'eloquent-prun':264 'eloquent-query-scop':222 'eloquent-relationship':238 'eloquent-soft-delet':256 'eloquent-vector-search':272 'encapsul':175 'essenti':407 'event':180,184,232,585,620 'exampl':931,954,958 'exist':390,402,536,543 'expand':980 'explan':928,948,956,960 'extend':439,505,670,787 'extract':142 'facad':590,782 'factori':644 'featur':189 'file':389,401,925,938 'fillabl':675 'fn':759,912 'folder':190 'foreach':860,884 'foreignid':802,808 'form':80,310,313,340,343,411,489 'formrequest':502,506 'foundat':500 'fresh':632 'frontmatt':941 'full':970 'function':442,468,508,519,553,595,602,610,690,701,710,721,736,752,790,796,845 'get':883,904,918 'good':957 'guid':43,976 'guidelin':65 'happen':448 'hasfactori':645,673 'high':110,116,121,285,337,375 'hook':369 'http':417,421,426,435,496,501 'id':534,538,545,680,699,747,800,804,810,837,843 'illumin':434,499,588,641,647,652,658,664,770,775,780 'impact':95,945 'implement':77 'index':830,835,841 'individu':923 'inject':331,332 'int':740 'invok':299 'involv':26 'job':199 'laravel':2,5,21,27,36,45,58,85,87,202,280,961 'laravel-best-practic':1 'larg':220 'latest':915 'least':564 'limit':916 'listen':186 'load':211,852,872,897,907 'logic':144,228,372 'maintain':57 'make':757 'mass':378,382 'matter':952 'max':526 'medium':125,130,386,398 'messag':554 'metadata':943 'method':304,307 'middlewar':324,326 'migrat':16,73,764,772,773,788 'min':531 'model':15,69,231,431,577,581,634,639,650,671 'must':561 'mutat':253,750 'n':213,854 'name':867,891 'namespac':415,494,572,637 'nest':364,895 'new':621,785 'notif':600,625 'notificationservic':599 'notifyfollow':626 'nullabl':540,548,827 'object':170,174 'observ':234 'old':270 'organ':191 'pattern':35,159,167,408,569 'per':869 'perf':126 'perform':124,385 'pgvector':279 'php':34,413,414,492,493,570,571,635,636,767,768,853,964 'post':432,453,454,461,464,472,473,475,483,486,516,559,582,604,605,606,612,613,623,627,629,631,669,795,850,857,858,861,863,865,870,877,878,885,887,889,898,899,908,909 'postcontrol':438 'postpublish':586,622 'posts.show':460,482 'postservic':593 'practic':4,10,39,42,766 'prefix':96 'prevent':212 'prioriti':92,93 'privat':597 'problem':856 'process':219 'proper':243,327 'protect':380,674,683,751 'prune':266 'public':441,467,507,518,552,594,601,689,700,709,720,735,789,844 'publish':546,603,615,619,681,685,729,732,825,838 'purpos':153 'queri':76,215,224,227,724,727,739,744,833,868,875,894,913,914 'queue':196,200 'quick':132 'read':922 'readon':598 'record':271 'recoveri':263 'redirect':458,480 'redirectrespons':436,446,474 'refer':63,133,969 'relat':655,661 'relationship':240,242,688 'repositori':158,163 'request':81,115,311,314,336,341,344,412,422,427,445,451,471,477,490,497 'requir':524,529,535 'resourc':288,291,303,306,318 'respons':321 'rest':305 'return':457,479,511,522,556,607,630,693,704,713,726,743,755,784 'reusabl':226 'rout':109,197,201,284,459,481 'rule':50,89,349,352,356,388,400,520,924,937,979 'rules/_sections.md':935 'rules/arch-service-classes.md':932 'rules/eloquent-eager-loading.md':933 'rules/validation-form-requests.md':934 'safe':260 'scalabl':56 'schema':777,783,793,848 'scope':225,719 'scopebycategori':737 'scopepublish':722 'search':275,277 'sec':122,377 'sec-mass-assign':376 'secur':120,374 'semant':276 'servic':18,71,140,146,567,574 'set':758 'side':236 'singl':152,295,297 'single-purpos':151 'skill' 'skill-laravel-best-practices' 'slug':677,818 'soft':258 'source-asyrafhussin' 'specif':966 'status':618 'store':443 'storepostrequest':423,444,504 'string':525,530,760,814,817 'structur':20,86,99,136 'success':463,466,485,488 'support':589,781 'tabl':798,799,801,807,813,816,820,823,828,834,840 'tag':539,542,544,711,716,882,903,946 'task':25 'text':821 'timestamp':824,829 'titl':523,676,753,815,944 'topic-agent-rules' 'topic-agent-skills' 'topic-ai-agents' 'topic-ai-slop' 'topic-claude-code' 'topic-code-quality' 'topic-code-review' 'topic-codex' 'topic-cursor' 'topic-laravel' 'topic-nodejs' 'topic-react' 'total':876 'transact':609 'transfer':169 'transform':254,319 'trigger':23 'ucfirst':762 'uniqu':819 'updat':469,476,487,614 'updatepostrequest':428,470 'use':11,162,233,290,312,342,419,424,429,433,498,575,579,583,587,611,640,646,651,657,663,672,769,774,779,921 'user':513,578,696,698,803,836 'valid':17,78,114,117,118,335,339,347,354,358,360,362,363,367,371,447,450,452,456,478 'validation-after-hook':366 'validation-array-valid':359 'validation-conditional-rul':353 'validation-custom-rul':346 'validation-form-request':338 'valu':173,761,763 'vector':274 'void':792,847 'wherenotnul':728 'withtimestamp':718 'write':72 'yaml':940 'yet':391,403","prices":[{"id":"dddc518f-4500-4c08-9896-035de0bf3ff0","listingId":"e8b5cab2-b24f-47bc-8399-a0eaee656049","amountUsd":"0","unit":"free","nativeCurrency":null,"nativeAmount":null,"chain":null,"payTo":null,"paymentMethod":"skill-free","isPrimary":true,"details":{"org":"AsyrafHussin","category":"agent-skills","install_from":"skills.sh"},"createdAt":"2026-05-16T18:57:14.193Z"}],"sources":[{"listingId":"e8b5cab2-b24f-47bc-8399-a0eaee656049","source":"github","sourceId":"AsyrafHussin/agent-skills/laravel-best-practices","sourceUrl":"https://github.com/AsyrafHussin/agent-skills/tree/main/skills/laravel-best-practices","isPrimary":false,"firstSeenAt":"2026-05-16T18:57:14.193Z","lastSeenAt":"2026-05-18T18:58:24.452Z"}],"details":{"listingId":"e8b5cab2-b24f-47bc-8399-a0eaee656049","quickStartSnippet":null,"exampleRequest":null,"exampleResponse":null,"schema":null,"openapiUrl":null,"agentsTxtUrl":null,"citations":[],"useCases":[],"bestFor":[],"notFor":[],"kindDetails":{"org":"AsyrafHussin","slug":"laravel-best-practices","github":{"repo":"AsyrafHussin/agent-skills","stars":39,"topics":["agent-rules","agent-skills","ai-agents","ai-slop","claude-code","code-quality","code-review","codex","cursor","laravel","nodejs","react","technical-debt","typescript","windsurf"],"license":"mit","html_url":"https://github.com/AsyrafHussin/agent-skills","pushed_at":"2026-05-16T19:24:02Z","description":"Agent skills for AI coding agents (Claude Code, Cursor, Codex, Windsurf) — Laravel, React, TypeScript, MySQL, code quality, technical debt, documentation, and security.","skill_md_sha":"05a8219e7d08691b38dffe6515a2251d4cc7eed8","skill_md_path":"skills/laravel-best-practices/SKILL.md","default_branch":"main","skill_tree_url":"https://github.com/AsyrafHussin/agent-skills/tree/main/skills/laravel-best-practices"},"layout":"multi","source":"github","category":"agent-skills","frontmatter":{"name":"laravel-best-practices","license":"MIT","description":"Laravel 13 conventions and best practices. Use when creating controllers, models, migrations, validation, services, or structuring Laravel applications. Triggers on tasks involving Laravel architecture, Eloquent, database, API development, or PHP patterns."},"skills_sh_url":"https://skills.sh/AsyrafHussin/agent-skills/laravel-best-practices"},"updatedAt":"2026-05-18T18:58:24.452Z"}}