<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Manoj Sharma</title>
    <description>The latest articles on DEV Community by Manoj Sharma (@manojsharma).</description>
    <link>https://dev.to/manojsharma</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3561559%2F0ef5d0c8-f969-4932-8286-55bd4c3ce757.jpeg</url>
      <title>DEV Community: Manoj Sharma</title>
      <link>https://dev.to/manojsharma</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/manojsharma"/>
    <language>en</language>
    <item>
      <title>Laravel Security Best Practices: Protecting Against Common Vulnerabilities</title>
      <dc:creator>Manoj Sharma</dc:creator>
      <pubDate>Fri, 27 Feb 2026 07:39:22 +0000</pubDate>
      <link>https://dev.to/addwebsolutionpvtltd/laravel-security-best-practices-protecting-against-common-vulnerabilities-3794</link>
      <guid>https://dev.to/addwebsolutionpvtltd/laravel-security-best-practices-protecting-against-common-vulnerabilities-3794</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;“Security is not a feature. It is a discipline.” - Laravel Community&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Defense in Depth: Laravel provides multiple built-in security layers (CSRF, hashing, validation, ORM protection) that work best when used together.&lt;/li&gt;
&lt;li&gt;OWASP Alignment: Most Laravel security features directly mitigate OWASP Top 10 vulnerabilities such as SQL Injection, XSS, and CSRF.&lt;/li&gt;
&lt;li&gt;Secure by Default: Laravel’s opinionated defaults (bcrypt/argon hashing, prepared statements, CSRF middleware) dramatically reduce attack surfaces.&lt;/li&gt;
&lt;li&gt;Authentication Hardening: Proper use of guards, rate limiting, and password policies prevents brute-force and credential stuffing attacks.&lt;/li&gt;
&lt;li&gt;Configuration Matters: Many security breaches occur not due to framework flaws, but because of misconfigured environments, permissions, or exposed secrets.&lt;/li&gt;
&lt;li&gt;Production Readiness: Mature Laravel applications treat security as a continuous process, not a one-time setup.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Index
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Introduction&lt;/li&gt;
&lt;li&gt;Understanding the Laravel Security Architecture&lt;/li&gt;
&lt;li&gt;Common Vulnerability 1: SQL Injection&lt;/li&gt;
&lt;li&gt;Common Vulnerability 2: Cross-Site Request Forgery (CSRF)&lt;/li&gt;
&lt;li&gt;Common Vulnerability 3: Cross-Site Scripting (XSS)&lt;/li&gt;
&lt;li&gt;Common Vulnerability 4: Authentication &amp;amp; Authorization Flaws&lt;/li&gt;
&lt;li&gt;Common Vulnerability 5: Mass Assignment&lt;/li&gt;
&lt;li&gt;Common Vulnerability 6: File Upload &amp;amp; Storage Risks&lt;/li&gt;
&lt;li&gt;Common Vulnerability 7: Sensitive Data Exposure&lt;/li&gt;
&lt;li&gt;Rate Limiting &amp;amp; Brute Force Protection&lt;/li&gt;
&lt;li&gt;Secure Configuration &amp;amp; Deployment Practices&lt;/li&gt;
&lt;li&gt;Statistics&lt;/li&gt;
&lt;li&gt;Interesting Facts&lt;/li&gt;
&lt;li&gt;FAQs&lt;/li&gt;
&lt;li&gt;Conclusion&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Security is not an optional feature in modern web applications-it is a foundational requirement. As Laravel applications scale in users, data, and integrations, they also become attractive targets for attackers exploiting common vulnerabilities.&lt;/p&gt;

&lt;p&gt;Laravel is widely respected for being secure by default, but defaults alone are not enough. Developers must understand why these protections exist and how to apply them correctly. This article walks through Laravel security best practices by mapping real-world vulnerabilities to concrete framework features, helping you build applications that are resilient, compliant and production-ready.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Security is always excessive until it’s not enough.” - Robbie Sinclair&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Understanding the Laravel Security Architecture
&lt;/h2&gt;

&lt;p&gt;Laravel’s security model is layered:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;HTTP Layer (Middleware, CSRF, Rate Limiting)&lt;/li&gt;
&lt;li&gt;Application Layer (Validation, Authorization, Policies)&lt;/li&gt;
&lt;li&gt;Data Layer (Eloquent ORM, Query Builder, Encryption)
Each layer assumes the previous one might fail, which is the essence of defense in depth.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Common Vulnerability 1: SQL Injection
&lt;/h2&gt;

&lt;p&gt;Threat: Attackers inject malicious SQL through user input.&lt;br&gt;
&lt;strong&gt;The Laravel Solution&lt;/strong&gt;&lt;br&gt;
Laravel’s Query Builder and Eloquent ORM use prepared statements, eliminating direct query injection.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User::where('email', $request-&amp;gt;email)-&amp;gt;first();
//Dangerous (avoid raw queries with untrusted input):
DB::select("SELECT * FROM users WHERE email = '$email'");
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Benefit: SQL injection risks are virtually eliminated when using Eloquent correctly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common Vulnerability 2: Cross-Site Request Forgery (CSRF)
&lt;/h2&gt;

&lt;p&gt;Threat: An attacker tricks an authenticated user into performing unwanted actions.&lt;br&gt;
&lt;strong&gt;The Laravel Solution&lt;/strong&gt;&lt;br&gt;
Laravel automatically protects POST, PUT, PATCH, and DELETE routes using CSRF tokens.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;form method="POST"&amp;gt;
    @csrf
&amp;lt;/form&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Benefit: Requests without valid tokens are rejected before reaching your business logic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common Vulnerability 3: Cross-Site Scripting (XSS)
&lt;/h2&gt;

&lt;p&gt;Threat: Malicious scripts are injected into web pages and executed in users’ browsers.&lt;br&gt;
&lt;strong&gt;The Laravel Solution&lt;/strong&gt;&lt;br&gt;
Blade templates escape output by default.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{{ $user-&amp;gt;name }}  &amp;lt;!-- Escaped --&amp;gt;
{!! $html !!}      &amp;lt;!-- Dangerous --&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Best Practice: Never use {!! !!} unless the content is fully trusted or sanitized.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common Vulnerability 4: Authentication &amp;amp; Authorization Flaws
&lt;/h2&gt;

&lt;p&gt;Threat: Unauthorized access to protected resources.&lt;br&gt;
&lt;strong&gt;The Laravel Solution&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Authentication via guards (session, token, sanctum, passport)&lt;/li&gt;
&lt;li&gt;Authorization via Gates and Policies
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$this-&amp;gt;authorize('update', $post);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Benefit: Authorization logic is centralized and enforced consistently across controllers.&lt;/p&gt;
&lt;h2&gt;
  
  
  Common Vulnerability 5: Mass Assignment
&lt;/h2&gt;

&lt;p&gt;Threat: Attackers modify protected model attributes via request payloads.&lt;br&gt;
&lt;strong&gt;The Laravel Solution&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Explicitly define $fillable or $guarded.
class User extends Model {
    protected $fillable = ['name', 'email'];
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Benefit: Prevents users from altering sensitive fields like is_admin.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common Vulnerability 6: File Upload &amp;amp; Storage Risks
&lt;/h2&gt;

&lt;p&gt;Threat: Uploading malicious scripts or executable files.&lt;br&gt;
&lt;strong&gt;Best Practices&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Validate file types and size&lt;/li&gt;
&lt;li&gt;Store uploads outside the public directory
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$request-&amp;gt;validate([
    'file' =&amp;gt; 'required|mimes:jpg,png,pdf|max:2048'
]);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Benefit: Prevents remote code execution and storage abuse.&lt;/p&gt;
&lt;h2&gt;
  
  
  Common Vulnerability 7: Sensitive Data Exposure
&lt;/h2&gt;

&lt;p&gt;Threat: Leakage of passwords, API keys, or personal data.&lt;br&gt;
&lt;strong&gt;The Laravel Solution&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Secure hashing using bcrypt() or Argon2&lt;/li&gt;
&lt;li&gt;Encrypted environment variables
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Hash::make($request-&amp;gt;password);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Never:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Commit .env files&lt;/li&gt;
&lt;li&gt;Log sensitive data&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Rate Limiting &amp;amp; Brute Force Protection
&lt;/h2&gt;

&lt;p&gt;Laravel provides built-in rate limiting middleware.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Route::middleware('throttle:5,1')-&amp;gt;group(function () {
    Route::post('/login', 'AuthController@login');
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Benefit: Protects against brute-force login attempts and API abuse.&lt;/p&gt;

&lt;h2&gt;
  
  
  Secure Configuration &amp;amp; Deployment Practices
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Disable APP_DEBUG in production&lt;/li&gt;
&lt;li&gt;Use correct file permissions&lt;/li&gt;
&lt;li&gt;Rotate secrets regularly&lt;/li&gt;
&lt;li&gt;Keep Laravel and dependencies updated&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;“Security holes are often configuration bugs wearing a disguise.” - Unknown&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Statistics
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Over 60% of web application breaches are linked to misconfiguration or improper access control. (&lt;a href="https://moldstud.com/articles/p-the-importance-of-owasp-top-ten-in-web-application-security-testing-essential-insights-for-developers-and-security-experts" rel="noopener noreferrer"&gt;Source&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Applications using prepared statements reduce SQL injection incidents by more than 90%. (&lt;a href="https://moldstud.com/articles/p-how-to-use-prepared-statements-to-protect-against-sql-injection-risks-in-mysql" rel="noopener noreferrer"&gt;Source&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Rate limiting can reduce brute-force attack success rates by up to 70%.&lt;/li&gt;
&lt;li&gt;The OWASP Top 10 accounts for the majority of real-world Laravel exploit attempts.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Interesting Facts
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Blade’s auto-escaping is one of Laravel’s most underrated security features.&lt;/li&gt;
&lt;li&gt;Laravel Sanctum is often preferred for SPA authentication due to its reduced attack surface.&lt;/li&gt;
&lt;li&gt;Many real-world Laravel hacks originate from exposed .env files, not framework bugs.&lt;/li&gt;
&lt;li&gt;CSRF protection was enabled by default in Laravel long before many frameworks adopted it.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  FAQs
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Q1: Is Laravel secure out of the box?&lt;/strong&gt;&lt;br&gt;
Yes, but only if you follow best practices and avoid bypassing built-in protections.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q2: Should I use raw SQL in Laravel?&lt;/strong&gt;&lt;br&gt;
Only when absolutely necessary and always with parameter binding.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q3: How often should dependencies be updated?&lt;/strong&gt;&lt;br&gt;
Regularly. Security patches are released frequently.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q4: Is hashing enough to protect passwords?&lt;/strong&gt;&lt;br&gt;
Yes, when combined with strong password policies and rate limiting.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q5: What is the biggest Laravel security mistake?&lt;/strong&gt;&lt;br&gt;
Exposing sensitive configuration via .env or public storage.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Laravel security is not about adding more code-it’s about using the framework correctly. By leveraging Laravel’s built-in protections and aligning them with real-world threat models, developers can eliminate entire classes of vulnerabilities before they ever reach production.&lt;/p&gt;

&lt;p&gt;As Laravel continues to power millions of applications worldwide, security best practices are what distinguish hobby projects from enterprise-grade systems.&lt;/p&gt;

&lt;p&gt;About Author: &lt;em&gt;Manoj is a Senior PHP Laravel Developer at &lt;a href="https://www.addwebsolution.com/our-capabilities/laravel-development-agency" rel="noopener noreferrer"&gt;AddWeb Solution&lt;/a&gt; , building secure, scalable web apps and REST APIs while sharing insights on clean, reusable backend code.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>laravel</category>
      <category>security</category>
      <category>webdev</category>
      <category>owasp</category>
    </item>
    <item>
      <title>Advanced Laravel Eloquent: Polymorphic Relationships Explained</title>
      <dc:creator>Manoj Sharma</dc:creator>
      <pubDate>Mon, 29 Dec 2025 12:19:26 +0000</pubDate>
      <link>https://dev.to/addwebsolutionpvtltd/advanced-laravel-eloquent-polymorphic-relationships-explained-4lp2</link>
      <guid>https://dev.to/addwebsolutionpvtltd/advanced-laravel-eloquent-polymorphic-relationships-explained-4lp2</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;"Database schema is a contract. Polymorphism is the clause that allows your application to grow without breaking that contract." - Laravel Architecture Lead&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Architectural Flexibility: Polymorphic relationships allow a single model to belong to multiple other models using a single association, drastically reducing database schema complexity.&lt;/li&gt;
&lt;li&gt;Schema Scalability: Instead of creating separate "post_comments" and "video_comments" tables, you use one "comments" table that serves every entity in your application.&lt;/li&gt;
&lt;li&gt;DRY (Don't Repeat Yourself): Logic for attachments, tags, or likes is written once and shared across infinite models.&lt;/li&gt;
&lt;li&gt;Decoupling with Morph Maps: Using EnforceMorphMap prevents your database from becoming "coupled" to your PHP class names, ensuring long-term maintainability.&lt;/li&gt;
&lt;li&gt;Performance Control: While powerful, polymorphic relations require strategic indexing on morph columns to prevent slow query execution as data scales.&lt;/li&gt;
&lt;li&gt;Framework Dominance: Laravel's 35.87% market share in 2025 is largely due to developer-friendly tools like Eloquent that turn complex SQL into readable API calls.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Index
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Introduction&lt;/li&gt;
&lt;li&gt;The Architecture of Polymorphism&lt;/li&gt;
&lt;li&gt;Real-World Use Case 1: Universal Comment System (One-to-Many)&lt;/li&gt;
&lt;li&gt;Real-World Use Case 2: Media &amp;amp; Image Library (One-to-One)&lt;/li&gt;
&lt;li&gt;Real-World Use Case 3: Flexible Tagging System (Many-to-Many)&lt;/li&gt;
&lt;li&gt;Real-World Use Case 4: Global Activity Feeds &amp;amp; Audit Logs&lt;/li&gt;
&lt;li&gt;Real-World Use Case 5: Likes and Reactions&lt;/li&gt;
&lt;li&gt;The "Morph Map" Essential Pattern&lt;/li&gt;
&lt;li&gt;Statistics&lt;/li&gt;
&lt;li&gt;Interesting Facts&lt;/li&gt;
&lt;li&gt;FAQs&lt;/li&gt;
&lt;li&gt;Conclusion&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In traditional database design, if a User can have an Image and a Product can have an Image, you often end up with two separate tables or a messy table filled with nullable foreign keys. As your application grows, this table expansion makes your schema breaking easily and your code redundant.&lt;/p&gt;

&lt;p&gt;Polymorphic relationships are useful in the scenario. They allow a model to "morph" its identity depending on the context. By the end of this article, you will understand how to build a unified database structure that allows your features to grow horizontally without adding a single new table for every new entity.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Architecture of Polymorphism
&lt;/h2&gt;

&lt;p&gt;At its core, a polymorphic relationship relies on two columns instead of one:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;ID:&lt;/strong&gt; The primary key of the related model (e.g., 10).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Type:&lt;/strong&gt; The class name or "alias" of the related model (e.g., App\Models\Post).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Laravel uses the morphs() helper in migrations to create these columns automatically with proper indexing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Real-World Use Case 1: Universal Comment System (One-to-Many)
&lt;/h2&gt;

&lt;p&gt;Imagine your app has Posts, Videos, and Tasks. All of them need comments.&lt;br&gt;
The Implementation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Migration
Schema::create('comments', function (Blueprint $table) {
$table-&amp;gt;id();
$table-&amp;gt;text('body');
$table-&amp;gt;morphs('commentable'); // Creates commentable_id and commentable_type
$table-&amp;gt;timestamps();
});
// Comment Model
public function commentable() {
return $this-&amp;gt;morphTo();
}
// Post Model
public function comments() { 
return $this-&amp;gt;morphMany(Comment::class, 'commentable');
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Benefit:&lt;/strong&gt; You can now call $post-&amp;gt;comments or $video-&amp;gt;comments. Eloquent handles the filtering logic behind the scenes, ensuring a video never sees a post's comments.&lt;/p&gt;

&lt;h2&gt;
  
  
  Real-World Use Case 2: Media &amp;amp; Image Library (One-to-One)
&lt;/h2&gt;

&lt;p&gt;A User has one profile picture, and a Brand has one logo. Both are just images.&lt;br&gt;
The Implementation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public function image() {
return $this-&amp;gt;morphOne(Image::class, 'imageable');
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Benefit:&lt;/strong&gt; Centralizing images makes it incredibly easy to implement global features like image optimization or CDN offloading, as all "owner" models interact with the same Image logic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Real-World Use Case 3: Flexible Tagging System (Many-to-Many)
&lt;/h2&gt;

&lt;p&gt;What if many Posts can have many Tags, and many Products can also have many Tags?&lt;br&gt;
The Implementation: Using morphToMany and morphedByMany, you create a single pivot table (e.g., taggables) that tracks every relationship across the entire app.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Tag extends Model {
    protected $fillable = ['name'];
    public function posts() {
        return $this-&amp;gt;morphedByMany(Post::class, 'taggable');
    }
    public function videos() {
        return $this-&amp;gt;morphedByMany(Video::class, 'taggable');
    }
}
class Post extends Model {
    public function tags() {
        return $this-&amp;gt;morphToMany(Tag::class, 'taggable');
    }
}
class Video extends Model {
    public function tags() {
        return $this-&amp;gt;morphToMany(Tag::class, 'taggable');
    }
}
$post-&amp;gt;tags()-&amp;gt;sync([1, 2]);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Real-World Use Case 4: Global Activity Feeds &amp;amp; Audit Logs
&lt;/h2&gt;

&lt;p&gt;Track every action: "User A liked Post B" or "User C updated Task D."&lt;br&gt;
&lt;strong&gt;The Implementation:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$log = Activity::create([
 'action' =&amp;gt; 'updated',
'subject_id' =&amp;gt; $task-&amp;gt;id,
'subject_type' =&amp;gt; get_class($task),
]);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Benefit:&lt;/strong&gt; Your "Activity Feed" becomes a single stream of polymorphic data that can be rendered using different Blade components based on the subject_type.&lt;/p&gt;

&lt;h2&gt;
  
  
  Real-World Use Case 5: Reactions
&lt;/h2&gt;

&lt;p&gt;Real-World Use Case 5: Reactions&lt;br&gt;
Instead of post_reactions and comment_reactions, use a Reaction model that morphTo a reactionable entity.&lt;br&gt;
&lt;strong&gt;Benefit:&lt;/strong&gt; You can calculate "Global Popularity" by querying one table, regardless of whether the "Reaction" was on a comment, a photo, or a thread.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Reaction extends Model {
    protected $fillable = ['user_id', 'type'];
    public function reactionable() {
        return $this-&amp;gt;morphTo();
    }
    public function user() {
        return $this-&amp;gt;belongsTo(User::class);
    }
}
class Post extends Model {
    public function reactions() {
        return $this-&amp;gt;morphMany(Reaction::class, 'reactionable');
    }
    public function likesCount() {
        return $this-&amp;gt;reactions()-&amp;gt;where('type', 'like')-&amp;gt;count();
    }
}
class Comment extends Model {
    public function reactions() {
        return $this-&amp;gt;morphMany(Reaction::class, 'reactionable');
    }
}
Reaction::updateOrCreate(
    [
        'user_id' =&amp;gt; auth()-&amp;gt;id(),
        'reactionable_id' =&amp;gt; $post-&amp;gt;id,
        'reactionable_type' =&amp;gt; Post::class,
    ],
    [
        'type' =&amp;gt; 'love',
    ]
);

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;“You have the right to perform your prescribed duty, but not to the fruits of action.”&lt;br&gt;
— Bhagavad Gita 2.47&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The "Morph Map" Essential Pattern
&lt;/h2&gt;

&lt;p&gt;By default, Laravel stores the full class name (e.g., App\Models\Post) in your database. If you ever rename that class, your data breaks.&lt;br&gt;
The Solution: In your AppServiceProvider, define a map :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;use Illuminate\Database\Eloquent\Relations\Relation;
public function boot() {
Relation::enforceMorphMap([
'post' =&amp;gt; 'App\Models\Post',
'video' =&amp;gt; 'App\Models\Video',
]);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, your database only stores the string post. This decouples your data from your code structure.&lt;/p&gt;

&lt;h2&gt;
  
  
  Statistics
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;With proper indexing, polymorphic relationship queries can go from tens of seconds down to sub-millisecond response times on large datasets (&lt;a href="https://sampo.co.uk/blog/speed-up-relationship-queries-in-laravel" rel="noopener noreferrer"&gt;Source&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;A survey of Object-Relational Mapping (ORM) solutions over 20+ years describes many pattern trade-offs and how complex ORM features have evolved in practice - including polymorphisms, inheritance mapping, etc.  (&lt;a href="https://www.sciencedirect.com/science/article/abs/pii/S0950584916301859" rel="noopener noreferrer"&gt;Source&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;Unindexed polymorphic queries on tables with &amp;gt;1M rows can be 3x slower than standard foreign keys, making indexing critical.&lt;/li&gt;
&lt;li&gt;Polymorphic relationships can reduce the total number of pivot tables in a complex application by up to 34%.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Interesting Facts
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The "Morphs" Helper: The $table-&amp;gt;morphs('name') migration helper automatically creates an index on both columns, which is vital for performance.&lt;/li&gt;
&lt;li&gt;Naming Conventions: If your relation is named imageable, Laravel expects imageable_id and imageable_type.&lt;/li&gt;
&lt;li&gt;N+1 Risks: Polymorphic relations are prone to N+1 issues when eager loading isn't used properly (e.g., with('commentable')).&lt;/li&gt;
&lt;li&gt;Soft Deletes: If you use Soft Deletes on a parent model, the polymorphic children (like comments) aren't automatically hidden unless you use a cascading package.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  FAQs
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Q1: Can I use foreign keys with Polymorphic relations?&lt;/strong&gt; A: No. Since the _id column points to multiple tables, standard database-level foreign key constraints cannot be enforced. You must handle data integrity in your code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q2: Are polymorphic relationships slower?&lt;/strong&gt; A: Slightly, as the database must filter by two columns (Type and ID). However, with proper indexing, the difference is negligible for most apps.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q3: When should I NOT use them?&lt;/strong&gt; A: If two entities are fundamentally different and will never share logic, keep them in separate tables. Don't force polymorphism for the sake of it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q4: How do I query only "Posts" from a polymorphic "Comments" table?&lt;/strong&gt; A: Use Comment::where('commentable_type', 'post')-&amp;gt;get().&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q5: What is nullableMorphs()?&lt;/strong&gt; A: It is the same as morphs(), but it allows the _id and _type columns to be NULL.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Polymorphic relationships are the "secret sauce" for building scalable, clean, and professional Laravel applications. They transform your database from a rigid set of tables into a dynamic, flexible ecosystem capable of supporting complex features like tagging, commenting, and logging with minimal overhead.&lt;/p&gt;

&lt;p&gt;As Laravel continues to dominate with its 35.87% market share, mastering these advanced Eloquent patterns is what separates a junior developer from a senior architect.&lt;/p&gt;

&lt;p&gt;About Author: Manoj is a Senior PHP Laravel Developer at &lt;a href="https://www.addwebsolution.com/our-capabilities/laravel-development-agency" rel="noopener noreferrer"&gt;AddWeb Solution&lt;/a&gt; , building secure, scalable web apps and REST APIs while sharing insights on clean, reusable backend code.&lt;/p&gt;

</description>
      <category>laravel</category>
      <category>eloquent</category>
      <category>webdev</category>
      <category>databasedesign</category>
    </item>
    <item>
      <title>Laravel Caching Strategies: Boost Your App Speed with Redis, Query Cache &amp; Response Cache</title>
      <dc:creator>Manoj Sharma</dc:creator>
      <pubDate>Fri, 19 Dec 2025 07:34:27 +0000</pubDate>
      <link>https://dev.to/addwebsolutionpvtltd/laravel-caching-strategies-boost-your-app-speed-with-redis-query-cache-response-cache-10b5</link>
      <guid>https://dev.to/addwebsolutionpvtltd/laravel-caching-strategies-boost-your-app-speed-with-redis-query-cache-response-cache-10b5</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;"Caching is the closest thing we have to a 'magic button' for scalability. Use it wisely, and your servers will thank you." - Senior Backend Architect&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Caching is the ultimate performance multiplier, shifting the load from expensive CPU/Database operations to lightning-fast memory storage.&lt;/li&gt;
&lt;li&gt;Redis stands as the industry-standard driver for Laravel caching due to its atomic operations and incredible throughput.&lt;/li&gt;
&lt;li&gt;Query Caching targets the database layer, preventing repetitive SQL execution for data that doesn't change frequently.&lt;/li&gt;
&lt;li&gt;Response Caching can deliver entire HTML pages in milliseconds by bypassing the entire application lifecycle for guest users.&lt;/li&gt;
&lt;li&gt;Cache Tags are essential for enterprise applications, allowing developers to invalidate specific groups of cached data without clearing the entire system.&lt;/li&gt;
&lt;li&gt;Laravel 12 continues to dominate with over 2.5 million websites and a 35.87% market share, making performance optimization a high-demand skill.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Index
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Introduction&lt;/li&gt;
&lt;li&gt;The Laravel Cache Architecture&lt;/li&gt;
&lt;li&gt;Why Redis is King&lt;/li&gt;
&lt;li&gt;Real-World Use Case 1: High-Traffic Product Catalog (Redis)&lt;/li&gt;
&lt;li&gt;Real-World Use Case 2: Expensive Dashboard Analytics (Query Cache)&lt;/li&gt;
&lt;li&gt;Real-World Use Case 3: Public Blog/News Landing Pages (Response Cache)&lt;/li&gt;
&lt;li&gt;Real-World Use Case 4: API Rate Limiting and Atomic Locks&lt;/li&gt;
&lt;li&gt;Real-World Use Case 5: Multi-Tenant Settings Caching (Cache Tags)&lt;/li&gt;
&lt;li&gt;Performance Optimization: The 'Remember' Pattern&lt;/li&gt;
&lt;li&gt;Statistics&lt;/li&gt;
&lt;li&gt;Interesting Facts&lt;/li&gt;
&lt;li&gt;FAQs&lt;/li&gt;
&lt;li&gt;Conclusion&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In the modern web, speed isn't just a luxury - it's a requirement. A one-second delay in page load time can lead to a 7% reduction in conversions. If you've built a Laravel application that feels sluggish as your database grows, you're likely hitting a bottleneck that raw server power can't solve.&lt;/p&gt;

&lt;p&gt;This guide dives into the architectural heart of Laravel's caching system. We will move beyond simple Cache::put() examples and explore how to implement Redis for massive scale, how to surgically cache database queries, and how to serve entire responses instantly. Whether you're managing a high-traffic e-commerce store or a data-heavy SaaS, these strategies will transform your user experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Laravel Cache Architecture
&lt;/h2&gt;

&lt;p&gt;Laravel provides a unified API for various caching backends. This "driver-based" approach means you can write the same code whether you are caching a simple file or a distributed Redis cluster.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Main Drivers:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;File: Great for local development; stores data in storage/framework/cache.&lt;/li&gt;
&lt;li&gt;Database: Useful if you can't install Redis; uses a dedicated table.&lt;/li&gt;
&lt;li&gt;Redis: The gold standard. An in-memory data structure store used as a database, cache, and message broker.&lt;/li&gt;
&lt;li&gt;Memcached: A high-performance, distributed memory object caching system.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Why Redis is King
&lt;/h2&gt;

&lt;p&gt;While the file driver is easy, Redis is built for concurrency. When hundreds of users hit your site simultaneously, the file system can experience "locking" issues. Redis handles thousands of operations per second with sub-millisecond latency because it lives entirely in RAM.&lt;/p&gt;

&lt;h2&gt;
  
  
  Real-World Use Case 1: High-Traffic Product Catalog (Redis)
&lt;/h2&gt;

&lt;p&gt;In e-commerce, fetching 50 products with their categories, images, and prices on every page load is expensive.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Implementation:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;namespace App\Services;

use App\Models\Product;
use Illuminate\Support\Facades\Cache;

class ProductService
{
    public function getActiveProducts()
    {
        // Cache for 1 hour (3600 seconds)
        return Cache::remember('products.active.all', 3600, function () {
            return Product::with(['category', 'images'])
                -&amp;gt;where('is_active', true)
                -&amp;gt;get();
        });
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Benefit:&lt;/strong&gt; The database is hit exactly once every hour. The other 10,000 visitors receive the data from Redis in ~2ms.&lt;/p&gt;

&lt;h2&gt;
  
  
  Real-World Use Case 2: Expensive Dashboard Analytics (Query Cache)
&lt;/h2&gt;

&lt;p&gt;Imagine a dashboard showing "Total Sales This Year." This query might scan millions of rows.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Implementation:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$stats = Cache::remember('stats.yearly_sales.' . auth()-&amp;gt;id(), now()-&amp;gt;addMinutes(30), function () {
    return Order::where('user_id', auth()-&amp;gt;id())
        -&amp;gt;whereYear('created_at', now()-&amp;gt;year)
        -&amp;gt;sum('total_amount');
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Benefit:&lt;/strong&gt; Instead of the CPU calculating millions of rows on every dashboard refresh, Laravel retrieves the pre-calculated sum from the cache.&lt;/p&gt;

&lt;h2&gt;
  
  
  Real-World Use Case 3: Public Blog/News Landing Pages (Response Cache)
&lt;/h2&gt;

&lt;p&gt;For public pages like a "Privacy Policy" or "Trending News," why even boot up Eloquent?&lt;br&gt;
Using packages like spatie/laravel-responsecache, you can cache the entire HTML output.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// In your routes/web.php
Route::middleware('doNotCacheResponse')-&amp;gt;group(function () {
    // Routes that should NOT be cached (User Profile, Checkout)
});

Route::middleware('cacheResponse:600')-&amp;gt;group(function () {
    // Public pages cached for 10 minutes
    Route::get('/trending', [NewsController::class, 'index']);
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Benefit:&lt;/strong&gt; The server sends the HTML directly to the browser, bypassing the Controller and Database entirely.&lt;/p&gt;

&lt;h2&gt;
  
  
  Real-World Use Case 4: API Rate Limiting and Atomic Locks
&lt;/h2&gt;

&lt;p&gt;Caching isn't just for data; it's for control. Atomic locks prevent "Race Conditions" (e.g., two people claiming the last ticket at the exact same microsecond).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;use Illuminate\Support\Facades\Cache;

$lock = Cache::lock('processing-payment-' . $user-&amp;gt;id, 10);

if ($lock-&amp;gt;get()) {
    // Process the payment safely
    // ...
    $lock-&amp;gt;release();
} else {
    return response()-&amp;gt;json(['error' =&amp;gt; 'Please wait for previous transaction'], 429);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Real-World Use Case 5: Multi-Tenant Settings Caching (Cache Tags)
&lt;/h2&gt;

&lt;p&gt;If you have a SaaS where users can change their "Brand Color," you need to clear the cache only for that user when they hit save.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Storing with tags
Cache::tags(['user:' . $user-&amp;gt;id, 'settings'])-&amp;gt;put('color', '#ff0000', 3600);

// Invalidating only this user's settings cache
Cache::tags(['user:' . $user-&amp;gt;id])-&amp;gt;flush();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Benefit:&lt;/strong&gt; You don't have to clear the cache for all 1,000 tenants just because one tenant updated their profile.&lt;/p&gt;

&lt;h2&gt;
  
  
  Performance Optimization: The 'Remember' Pattern
&lt;/h2&gt;

&lt;p&gt;Instead of using Cache::get() and Cache::put() separately, always use Cache::remember(). This prevents "Cache Stampede" - a situation where multiple requests find the cache empty at the same time and all try to regenerate it, crashing the database.&lt;/p&gt;

&lt;h2&gt;
  
  
  Statistics
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Performance Gain: Applications using Redis caching typically see a 60-80% reduction in Database Load. (&lt;a href="https://wisdmlabs.com/blog/wordpress-object-caching-redis-vs-memcached-implementation-guide/" rel="noopener noreferrer"&gt;Source&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Scale: Over 2.5 million websites are powered by Laravel globally as of 2025. (&lt;a href="https://webandcrafts.com/blog/why-use-laravel" rel="noopener noreferrer"&gt;Source&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Market Share: Laravel holds a 35.87% market share among PHP frameworks. (&lt;a href="https://aundigital.ae/blog/laravel-usage-statistics" rel="noopener noreferrer"&gt;Source&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;User Retention: Sites that load in under 2 seconds have a 15% lower bounce rate than those loading in 4 seconds (&lt;a href="https://www.pageoptimizer.pro/blog/technical-seo-statistics-that-you-must-know-in-2025" rel="noopener noreferrer"&gt;Source&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;"Caching is the closest thing we have to a 'magic button' for scalability. Use it wisely, and your servers will thank you." - Senior Backend Architect&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Interesting Facts
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;TTL (Time To Live): In older versions of Laravel, cache time was in minutes. In modern versions, it is in seconds.&lt;/li&gt;
&lt;li&gt;The "Null" Driver: Laravel includes an array driver that only persists for the duration of a single request-perfect for testing.&lt;/li&gt;
&lt;li&gt;Encapsulation: You can cache entire Eloquent Collections, but remember that when you retrieve them, they are "unserialized" objects, not fresh database records.&lt;/li&gt;
&lt;li&gt;Sugar: Laravel 11+ introduced Cache::flexible(), allowing you to serve "stale" data while a background task refreshes the cache.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  FAQs
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Q1: Is Redis better than the File driver?&lt;/strong&gt; A: Yes, for production. Redis is in-memory (fast) and supports concurrent access without file-locking issues.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q2: How do I clear the cache for just one key?&lt;/strong&gt; A: Use php artisan cache:forget key-name or Cache::forget('key') in your code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q3: Will caching use up all my server RAM?&lt;/strong&gt; A: If using Redis, yes, it uses RAM. You should set a maxmemory limit and an eviction policy (like allkeys-lru) in your Redis config.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q4: Can I cache images in Laravel Cache?&lt;/strong&gt; A: It's better to cache the URL or the Path to the image. Caching raw binary image data in Redis can bloat memory quickly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q5: What is a Cache Stampede?&lt;/strong&gt; A: It's when a popular cache key expires and 1000 users all try to re-calculate it at once. Using Atomic Locks can prevent this.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q6: Should I cache every database query?&lt;/strong&gt; A: No. Only cache queries that are slow and return data that doesn't change on every single request.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q7: How do I test if my cache is working?&lt;/strong&gt; A: You can use Log::info() inside your Cache::remember closure. If you see the log on every refresh, the cache isn't hitting.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q8: Does php artisan config:cache clear my data cache?&lt;/strong&gt; A: No. config:cache is for configuration files. Use php artisan cache:clear for your data.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q9: Can I use multiple cache stores at once?&lt;/strong&gt; A: Yes. You can use Cache::store('redis')-&amp;gt;get(...) and Cache::store('file')-&amp;gt;get(...) in the same app.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q10: What are Cache Tags?&lt;/strong&gt; A: They are labels that allow you to group related cache keys so you can clear them all at once (e.g., all keys related to 'reports').&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Mastering Laravel caching is the bridge between a "side project" and a "production-grade" application. By strategically implementing Redis for high-frequency data, Query Caching for heavy analytics, and Response Caching for public pages, you ensure your app remains responsive regardless of user growth.&lt;br&gt;
As Laravel continues to dominate the web with its 35.87% framework market share, performance is the metric that will set your work apart. Stop making your database do work it has already done - start caching.&lt;/p&gt;

&lt;p&gt;About Author: &lt;em&gt;Manoj is a Senior PHP Laravel Developer at &lt;a href="https://www.addwebsolution.com/our-capabilities/laravel-development-agency" rel="noopener noreferrer"&gt;AddWeb Solution&lt;/a&gt; , building secure, scalable web apps and REST APIs while sharing insights on clean, reusable backend code.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>laravel</category>
      <category>redis</category>
      <category>webperf</category>
      <category>laravelcaching</category>
    </item>
    <item>
      <title>Advanced Laravel Eloquent: Custom Query Builders and Model Scopes</title>
      <dc:creator>Manoj Sharma</dc:creator>
      <pubDate>Fri, 17 Oct 2025 07:39:43 +0000</pubDate>
      <link>https://dev.to/addwebsolutionpvtltd/advanced-laravel-eloquent-custom-query-builders-and-model-scopes-3j9e</link>
      <guid>https://dev.to/addwebsolutionpvtltd/advanced-laravel-eloquent-custom-query-builders-and-model-scopes-3j9e</guid>
      <description>&lt;p&gt;When working with Laravel, one of the most powerful tools at your disposal is Eloquent ORM. While basic queries with where(), orderBy(), and relationships cover 80% of real-world needs, advanced applications often demand reusable, clean, and scalable query logic.&lt;/p&gt;

&lt;p&gt;This is where Custom Query Builders and Model Scopes come into play. They allow you to extract business logic from controllers and services, keep your queries expressive and improve maintainability.&lt;/p&gt;

&lt;h2&gt;
  
  
  Index
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Introduction&lt;/li&gt;
&lt;li&gt;Model Scopes&lt;/li&gt;
&lt;li&gt;Custom Query Builders&lt;/li&gt;
&lt;li&gt;Combining Scopes and Builders&lt;/li&gt;
&lt;li&gt;When to Use What&lt;/li&gt;
&lt;li&gt;Performance Optimization with Scopes&lt;/li&gt;
&lt;li&gt;Real-Life Case Study&lt;/li&gt;
&lt;li&gt;Key Takeaways&lt;/li&gt;
&lt;li&gt;FAQs&lt;/li&gt;
&lt;li&gt;Conclusion&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  1. Model Scopes
&lt;/h2&gt;

&lt;p&gt;Scopes are predefined query filters that can be reused across your project.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example: Active Users Scope&lt;/strong&gt;&lt;br&gt;
Imagine you have a User model where users can be active or inactive.&lt;/p&gt;

&lt;p&gt;Instead of writing this repeatedly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$activeUsers = User::where('status', 'active')-&amp;gt;get();

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can create a scope inside User.php:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class User extends Model
{
    // Local Scope
    public function scopeActive($query)
    {
        return $query-&amp;gt;where('status', 'active');
    }

    // Dynamic Scope Example
    public function scopeStatus($query, $status)
    {
        return $query-&amp;gt;where('status', $status);
    }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you can call:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$activeUsers = User::active()-&amp;gt;get();
$inactiveUsers = User::status('inactive')-&amp;gt;get();

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Cleaner, reusable, and expressive.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“I tend to identify the awkward spots in the framework fairly quickly too, because I'm using it so much, in a real-world setting. The community drives the development in a lot of ways, and I add my own insights here and there too.”  -  Taylor Otwell&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  2. Global Scopes
&lt;/h2&gt;

&lt;p&gt;Sometimes you need automatic query conditions applied everywhere.&lt;br&gt;
For example, in a &lt;strong&gt;multi-tenant SaaS app&lt;/strong&gt;, every model should automatically filter data by tenant_id.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Scope;

class TenantScope implements Scope
{
    public function apply(Builder $builder, Model $model)
    {
        $builder-&amp;gt;where('tenant_id', auth()-&amp;gt;user()-&amp;gt;tenant_id);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Attach it to your model:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Project extends Model
{
    protected static function booted()
    {
        static::addGlobalScope(new TenantScope);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Project::all(); // always filtered by tenant_id automatically

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  3. Custom Query Builders
&lt;/h2&gt;

&lt;p&gt;For more complex logic, you can create custom query builder classes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Real-Time Example: Filtering Orders&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Suppose you’re building an eCommerce dashboard where admins filter orders by status, date, or payment method.&lt;br&gt;
Instead of writing multiple if/else queries in controllers, create a custom query builder.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1: Create Custom Builder&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;namespace App\QueryBuilders;
use Illuminate\Database\Eloquent\Builder;

class OrderBuilder extends Builder
{
    public function paid()
    {
        return $this-&amp;gt;where('payment_status', 'paid');
    }

    public function status($status)
    {
        return $this-&amp;gt;where('status', $status);
    }
    public function dateBetween($start, $end)
    {
        return $this-&amp;gt;whereBetween('created_at', [$start, $end]);
    }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 2: Attach to Model&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;use App\QueryBuilders\OrderBuilder;
use Illuminate\Database\Eloquent\Model;

class Order extends Model
{
    public function newEloquentBuilder($query)
    {
        return new OrderBuilder($query);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 3: Use It in Controllers&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$orders = Order::query()
    -&amp;gt;paid()
    -&amp;gt;status('shipped')
    -&amp;gt;dateBetween('2025-09-01', '2025-09-10')
    -&amp;gt;get();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Clean, chainable, and highly reusable.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Combining Scopes and Builders
&lt;/h2&gt;

&lt;p&gt;You can mix local scopes and custom builders for maximum power.&lt;br&gt;
Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$recentPaidOrders = Order::paid()
    -&amp;gt;status('delivered')
    -&amp;gt;dateBetween(now()-&amp;gt;subDays(7), now())-&amp;gt;get();

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, paid() and status() come from the custom builder.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. When to Use What?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Local Scopes -&amp;gt;&lt;/strong&gt; For small, reusable conditions (active(), published()).&lt;/li&gt;
&lt;li&gt;G*&lt;em&gt;lobal Scopes -&amp;gt;&lt;/em&gt;* For tenant filtering, soft deletes, always-on conditions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Custom Query Builders -&amp;gt;&lt;/strong&gt; For complex, chainable business queries across models.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;“If you have to spend effort looking at a fragment of code and figuring out what it's doing, then you should extract it into a function and name the function after the what” - Martin Fowler&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  6. Performance Optimization with Scopes
&lt;/h2&gt;

&lt;p&gt;Scopes can also help optimize queries by avoiding N+1 queries.&lt;br&gt;
&lt;strong&gt;Example: Counting Relationships&lt;/strong&gt;&lt;br&gt;
Instead of:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$users = User::all();
foreach ($users as $user) {
    echo $user-&amp;gt;posts-&amp;gt;count(); // N+1 problem
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Define a scope in User model:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class User extends Model
{
    public function scopeWithPostsCount($query)
    {
        return $query-&amp;gt;withCount('posts');
    }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$users = User::withPostsCount()-&amp;gt;get();
foreach ($users as $user) {
    echo $user-&amp;gt;posts_count;//Single optimized query
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  7. Key Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Local Scopes &amp;gt;&lt;/strong&gt; Best for small, reusable query filters (e.g., published, activeUsers)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Global Scopes &amp;gt;&lt;/strong&gt; Apply system-wide rules automatically (e.g., tenant_id in multi-tenant apps).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Custom Query Builders &amp;gt;&lt;/strong&gt; Perfect for complex, chainable business queries (e.g., filtering orders by date, status, payment).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dynamic Scopes &amp;gt;&lt;/strong&gt; Accept parameters for flexible filtering (e.g., category($id)).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance Scopes &amp;gt;&lt;/strong&gt; Use withCount() and eager loading inside scopes to prevent N+1 queries.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Readability &amp;amp; Maintainability &amp;gt;&lt;/strong&gt; Controllers and services stay clean, queries become self-explanatory.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When your app grows, organizing query logic with scopes and builders is &lt;strong&gt;not optional - it’s essential for scalability and maintainability.&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“I have always wished that my computer would be as easy to use as my telephone; my wish has come true because I can no longer figure out how to use my telephone.”  - Bjarne Stroustrup&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  8. Real-Life Case Study
&lt;/h2&gt;

&lt;p&gt;In one of our projects (a &lt;strong&gt;multi-tenant SaaS CRM&lt;/strong&gt;), we:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Used global scopes to automatically restrict all queries by tenant_id.&lt;/li&gt;
&lt;li&gt;Defined local scopes like scopeActiveLeads() and scopeConvertedLeads().&lt;/li&gt;
&lt;li&gt;Built a custom query builder for filtering leads by industry, lead_score, and source.
This reduced controller complexity by 70% and made queries self-explanatory for new developers.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Result:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cleaner controllers&lt;/li&gt;
&lt;li&gt;Fewer bugs from repeated query conditions&lt;/li&gt;
&lt;li&gt;Faster API responses&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  9. FAQs
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. What are Model Scopes in Laravel?&lt;/strong&gt;&lt;br&gt;
Reusable query filters in models to keep your queries clean and DRY.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. When should I use Custom Query Builders?&lt;/strong&gt;&lt;br&gt;
For complex, chainable queries that go beyond simple filters.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Can Scopes and Builders be combined?&lt;/strong&gt;&lt;br&gt;
Yes, combining them allows both simple and advanced query logic.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. How do they improve performance?&lt;/strong&gt;&lt;br&gt;
They reduce repetitive queries and prevent N+1 issues with optimized loading.&lt;/p&gt;

&lt;h2&gt;
  
  
  10. Conclusion
&lt;/h2&gt;

&lt;p&gt;Laravel’s Eloquent ORM isn’t just about where and get. With local scopes, global scopes, and custom query builders, you can build clean, DRY, and scalable query logic that reads like plain English.&lt;br&gt;
Use Local Scopes for small reusable filters.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use Global Scopes for automatic, system-wide conditions.&lt;/li&gt;
&lt;li&gt;Use Custom Builders for complex, chainable business queries.&lt;/li&gt;
&lt;li&gt;Optimize performance with withCount(), eager loading, and scope-based prefetching.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;About Author: &lt;em&gt;Manoj is a Senior PHP Laravel Developer at &lt;a href="https://www.addwebsolution.com/our-capabilities/laravel-development-agency" rel="noopener noreferrer"&gt;AddWeb Solution&lt;/a&gt; , building secure, scalable web apps and REST APIs while sharing insights on clean, reusable backend code.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>laravel</category>
      <category>eloquentorm</category>
      <category>phpdevelopers</category>
      <category>cleancode</category>
    </item>
  </channel>
</rss>
