When building Laravel applications, you often write repeated query conditions. For example, if your app has users, you may want to fetch only active users in many places. Writing ->where('status', 'active') again and again can get messy.
This is where Laravel Query Scopes come in.
A query scope in Laravel is a way to define common query logic inside your Eloquent model. Once defined, you can reuse it across your application.
There are two types of scopes in Laravel:
-
Local Scopes – reusable query conditions you call manually.
-
Global Scopes – applied automatically to all queries of a model.
By using Laravel query scopes, you keep your code clean, reusable, and DRY (Don’t Repeat Yourself).
Why Use Laravel Query Scopes?
| Problem Without Scope | Solution With Scope |
|---|---|
You repeat the same where conditions in multiple queries. |
Define once in model, reuse everywhere. |
| Risk of mistakes if conditions change later. | Change in one place only (the scope). |
| Messy controllers and repositories. | Clean and readable query syntax. |
Real-world example:
-
If you need to fetch only published blog posts, instead of writing:
Post::where('status', 'published')->get();
everywhere, you can define a scopePublished() inside your Post model and call:
Post::published()->get();
Much cleaner, right?
Types of Scopes in Laravel
| Type | Description | Example |
|---|---|---|
| Local Scope | You define and call it manually. | User::active()->get() |
| Global Scope | Automatically applied to all queries of a model. | SoftDeletes trait (hides deleted rows automatically). |
1. Local Scopes in Laravel
A local scope is a method inside your model that starts with the prefix scope.
Example: Active Users
In User.php model:
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
// Local scope for active users
public function scopeActive($query)
{
return $query->where('status', 'active');
}
}
Now instead of writing:
$users = User::where('status', 'active')->get();
You can simply call:
$users = User::active()->get();
Benefit: Cleaner, reusable, easier to maintain.
Local Scope with Parameters
You can also pass parameters.
Example: Filter posts by category.
class Post extends Model
{
public function scopeCategory($query, $categoryId)
{
return $query->where('category_id', $categoryId);
}
}
Usage:
$techPosts = Post::category(3)->get();
Real-world use: Filtering blog posts based on selected category.
2. Global Scopes in Laravel
A global scope is applied to all queries of a model automatically.
Example: Only Published Posts
namespace App\Models;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
protected static function booted()
{
static::addGlobalScope('published', function (Builder $builder) {
$builder->where('status', 'published');
});
}
}
Now whenever you call:
It will only return posts with status = 'published'.
Real-world example:
-
Hide inactive products in an e-commerce store.
-
Hide banned users from a social app.
Removing Global Scope
Sometimes you may want to ignore a global scope.
Real-world example: Admins may need to see all posts (published + drafts).
Built-in Global Scope Example – SoftDeletes
Laravel already uses global scopes in features like SoftDeletes.
When you use the SoftDeletes trait in your model:
use Illuminate\Database\Eloquent\SoftDeletes;
class Post extends Model
{
use SoftDeletes;
}
All queries on Post will automatically exclude deleted rows.
👉 Example:
Post::all(); // excludes deleted posts
Post::withTrashed()->get(); // includes deleted posts
Combining Local and Global Scopes
You can use both together.
Example:
-
Global scope: Show only
status = active. -
Local scope: Further filter by role.
class User extends Model
{
protected static function booted()
{
static::addGlobalScope('active', function (Builder $builder) {
$builder->where('status', 'active');
});
}
public function scopeRole($query, $role)
{
return $query->where('role', $role);
}
}
Usage:
This fetches only active admins.
Real-World Use Cases of Query Scopes
| Use Case | Type of Scope | Example |
|---|---|---|
| Only active users | Global | User::all() (automatically filters) |
| Only published posts | Global | Post::all() |
| Filter posts by category | Local | Post::category(2)->get() |
| Products in stock | Local | Product::inStock()->get() |
| Orders by status | Local | Order::status('pending')->get() |
Performance & Best Practices
-
✅ Use local scopes for reusable filters.
-
✅ Use global scopes for rules that should always apply (e.g., hide inactive users).
-
✅ Keep scopes short and clear.
-
✅ Avoid overusing global scopes because they may confuse new developers.
-
✅ Always give parameters to local scopes if needed.
Example: Blog Application
Scenario:
You’re building a blog with posts. You want:
-
Show only published posts by default (global scope).
-
Ability to filter posts by author or category (local scopes).
Solution:
Post Model
Usage in Controller
This will fetch published posts by author 1 in category 3.
Table: Laravel Query Scope Keywords vs Examples
| Keyword | Example |
|---|---|
| laravel query scope | User::active()->get(); |
| laravel global scope | Post::all(); (only published posts) |
| laravel local scope | Product::inStock()->get(); |
| laravel eloquent scope | Defined in model for reusability |
| laravel model scope | scopeActive() method |
| laravel query scope example | Blog filtering posts |
| global scope in laravel | SoftDeletes |
| local scope in laravel example | Filtering by category |
Conclusion
-
Laravel query scope is a powerful feature to keep queries clean and reusable.
-
Use local scopes for conditions you call manually.
-
Use global scopes for conditions that must always apply.
-
Real-world apps like blogs, e-commerce, and CRMs heavily rely on scopes to simplify database queries.
In short:
-
If you’re repeating queries → use local scope.
-
If you always need a condition → use global scope.