Laravel 12 Eloquent Tips and Tricks for Beginners

1 Understanding Eloquent Relationships

One of the first things you will learn when using Laravel is how to define and work with Eloquent relationships. These relationships make it easy to fetch related records across different database tables. Understanding relationships is fundamental to writing efficient queries and avoiding performance pitfalls like the N+1 problem (covered in the next section).
One-to-Many Relationship Example
In this example, we will define a Post and Comment relationship where each post can have many comments. Post Model:
    
        class Post extends Model
        {
            public function comments()
            {
                return $this->hasMany(Comment::class);
            }
        }
     
Comment Model:
    
        class Comment extends Model
        {
            public function post()
            {
                return $this->belongsTo(Post::class);
            }
        }
     
Fetching Comments for a Post:
    
        $post = Post::find(1);
        $comments = $post->comments;
     
Laravel supports several other relationship types including one-to-one, many-to-many, has-many-through, and polymorphic relations. These are essential when building real-world applications like REST APIs in Laravel 12.

Laravel 12 Eloquent Tips and Tricks for Beginners

2 Use Attribute Casting for Automatic Data Transformation

Casting lets Eloquent automatically convert types when reading/writing to the database.
    
        // app/Models/User.php
        namespace App\Models;

        use Illuminate\Database\Eloquent\Model;
        use Illuminate\Database\Eloquent\Casts\Attribute;

        class User extends Model
        {
            protected $casts = [
                'is_admin' => 'boolean',
                'settings' => 'array',
                'born_at'  => 'datetime:Y-m-d',
                'data'     => 'json',           // Laravel 12+ improved json handling
            ];

            // Custom accessor (getter)
            protected function fullName(): Attribute
            {
                return Attribute::make(
                    get: fn ($value, $attributes) => $attributes['first_name'] . ' ' . $attributes['last_name'],
                );
            }
        }
     
Usage:
    
        $user = User::find(1);
        echo $user->is_admin;      // true/false instead of 1/0
        echo $user->full_name;     // "John Doe"
        $user->settings = ['theme' => 'dark'];  // auto JSON encoded
     
Eloquent ORM is one of the most powerful features in Laravel 12. It provides an elegant, ActiveRecord-style interface for working with your database — turning complex SQL operations into simple, expressive PHP code. Whether you are just starting with Laravel or looking to level up your skills, mastering Eloquent is essential for building efficient, maintainable applications.

In this comprehensive guide, we will walk you through 11 must-know Eloquent tips and tricks for Laravel 12. Each tip includes practical code examples that you can apply immediately in your projects. If you are new to Laravel 12, you may also want to check out our guide on How to Build a REST API in Laravel 12 or learn about Laravel 12 Routing and Middleware to strengthen your foundation before diving in.

3 Avoid N+1 Query Problem with Eager Loading

The infamous N+1 issue kills performance. Always eager load relationships when you know you will access them. This is one of the most impactful optimizations you can make in any Laravel application. For more performance strategies, see our full guide on Laravel 12 Performance Optimization Tips.
    
        // Bad - N+1 queries
        $posts = Post::all();
        foreach ($posts as $post) {
            echo $post->user->name;   // extra query per post!
        }

        // Good - one query for users
        $posts = Post::with('user')->get();

        foreach ($posts as $post) {
            echo $post->user->name;   // no extra queries
        }

        // Nested eager loading
        $posts = Post::with('user.profile', 'comments.user')->get();
     

Use withCount() for counting without loading full models:

    
       $posts = Post::withCount('comments')->get();
        echo $posts->first()->comments_count;
     

4 Local Scopes – Reusable Query Logic

Define reusable query constraints inside your model.
    
        // app/Models/Post.php
        class Post extends Model
        {
            public function scopePublished($query)
            {
                return $query->where('published_at', '<=', now())
                            ->where('is_draft', false);
            }

            public function scopePopular($query, $minViews = 1000)
            {
                return $query->where('views', '>=', $minViews);
            }
        }
     

Usage:

    
       $published = Post::published()->get();
        $popularPublished = Post::published()->popular(5000)->get();
     

5 Soft Deletes with Eloquent

Laravel provides a convenient way to handle soft deletes, which allow you to delete records without removing them from the database. This is useful for keeping records that might need to be restored later — for example, in audit logs, order histories, or content management systems.

Soft Deletes Example
In the Post model, add the SoftDeletes trait:
    
        use Illuminate\Database\Eloquent\SoftDeletes;

        class Post extends Model
        {
            use SoftDeletes;
        }
     
Make sure your migration includes the deleted_at column:
    
       $table->softDeletes(); // adds nullable deleted_at column
     
Now, when you delete a record, it is marked as deleted in the database but not actually removed:
    
       $post = Post::find(1);
       $post->delete();  // sets deleted_at timestamp
     
To retrieve soft-deleted records:
    
       $posts = Post::withTrashed()->get();  // includes soft-deleted
       $post->restore();  // restore a soft-deleted record
       $post->forceDelete();  // permanently remove
     

6 Accessors & Mutators – Clean Data Handling

Transform data on the fly.
    
        protected function firstName(): Attribute
        {
            return Attribute::make(
                get: fn ($value) => ucfirst($value),
                set: fn ($value) => strtolower($value),
            );
        }
     
Now $user->first_name is always capitalized, and stored lowercase.

7 Chunk Large Datasets to Avoid Memory Issues

If you are working with large datasets, loading all records into memory at once can crash your application. Use chunk() to process thousands of records safely in smaller batches:
    
       User::where('active', true)->chunk(200, function ($users) {
        foreach ($users as $user) {
            // Process user (e.g. send email)
            $user->notify(new WelcomeEmail());
        }
    });
     
Laravel 12 also supports lazy() collections for even more memory-efficient processing:
    
       User::where('active', true)->lazy()->each(function ($user) {
        $user->notify(new WelcomeEmail());
    });
     
For background processing of large jobs, consider using Laravel 12 Queues and Jobs to offload heavy operations.

8 Advanced Relationships Tricks

Conditional relationships & whereHas:
    
       // Users who have published posts in last 30 days
        $activeUsers = User::whereHas('posts', function ($query) {
            $query->where('published_at', '>=', now()->subDays(30));
        })->get();

        // Has many through with constraint
        class Country extends Model
        {
            public function posts()
            {
                return $this->hasManyThrough(
                    Post::class, User::class,
                    'country_id', 'user_id', 'id', 'id'
                )->where('published', true);
            }
        }
     

9 Custom Collections for Model-Specific Logic

    
       // app/Collections/PostCollection.php
        namespace App\Collections;

        use Illuminate\Database\Eloquent\Collection;

        class PostCollection extends Collection
        {
            public function published()
            {
                return $this->filter(fn($post) => $post->published_at?->isPast());
            }

            public function summaries()
            {
                return $this->map->only('title', 'excerpt');
            }
        }

        // In model:
        class Post extends Model
        {
            public function newCollection(array $models = [])
            {
                return new PostCollection($models);
            }
        }
     
Usage: $posts = Post::all()->published();

10 Model Factories with Mass Insert (Laravel 12+)

For efficient database seeding, you can combine factories with bulk insert() to generate large amounts of test data quickly — much faster than calling create() in a loop, since it avoids firing model events and individual INSERT queries.
    
      // database/factories/PostFactory.php
Post::factory()->count(100)->make()->toArray(); // prepare data without saving

// Bulk insert (faster than create() for large datasets)
Post::insert(
    Post::factory()->count(500)->make()->toArray()
);
     
Note: insert() does not trigger Eloquent events or set timestamps automatically. If you need timestamps, add them in your factory definition or use now() manually.

Table Of Content

11 Debugging Queries & Performance Tips

Enable query logging temporarily to inspect what Eloquent is doing behind the scenes:
    
      DB::enableQueryLog();
$users = User::with('posts')->get();
dd(DB::getQueryLog());
     
Other performance tips:
  • Use select() to load only needed columns: User::select('id', 'name')->get();
  • Prefer exists() over count() > 0 for checking record existence
  • Use database indexes on columns frequently used in where() clauses
  • Use toSql() to preview the generated SQL: Post::where('active', true)->toSql();
For a deeper dive into Laravel optimization, read our complete Laravel 12 Performance Optimization Guide. If you run into errors during debugging, our Common Laravel 12 Errors guide can help you troubleshoot quickly.

12 Conclusion

Mastering Eloquent in Laravel 12 makes you significantly more productive as a developer. Start with casting, eager loading, and scopes — they solve 80% of common database issues. As you get more comfortable, explore advanced relationships, custom collections, and chunking for production-ready applications.

Experiment with these tips in a fresh Laravel 12 project (composer create-project laravel/laravel laravel12-tips). Your future self (and your users) will thank you for faster, cleaner applications.

Continue Learning Laravel 12:
Revathi M - PHP and CodeIgniter Developer

Written by Revathi M

PHP Developer & Technical Writer · 10+ years building web applications with CodeIgniter and Laravel

Revathi specializes in PHP backend development, authentication systems, and REST API design. She writes practical, production-tested tutorials at Get Sample Code to help developers build secure applications faster.

Frequently Asked Questions

Laravel Eloquent is an ORM (Object-Relational Mapping) included with the Laravel framework. It provides an elegant ActiveRecord implementation for working with your database, allowing developers to interact with database tables using PHP model classes instead of writing raw SQL queries. Each model corresponds to a table, and you can define relationships, scopes, accessors, and mutators within your models.

The N+1 query problem occurs when your code executes one query to fetch a collection of records, and then runs an additional query for each record to fetch related data — resulting in N+1 total queries. For example, fetching 100 posts and then accessing each post's author triggers 101 queries. The solution is eager loading using the with() method, which reduces this to just 2 queries.

To use soft deletes in Laravel, add the SoftDeletes trait to your Eloquent model and ensure your database table has a deleted_at timestamp column (use $table->softDeletes() in your migration). When you call delete() on a model, Laravel sets the deleted_at timestamp instead of removing the row. You can retrieve soft-deleted records with withTrashed(), restore them with restore(), or permanently delete with forceDelete().

Query scopes in Laravel are reusable query constraints defined as methods in your Eloquent model. Local scopes are prefixed with scope (e.g., scopePublished) and can be chained fluently like Post::published()->get(). Global scopes automatically apply to all queries for a model. Scopes help keep your controllers clean by encapsulating common filtering logic inside the model itself.

Eager loading is a technique in Laravel where related models are loaded upfront in a single query, rather than being lazily loaded one at a time. By using Post::with('comments')->get(), Laravel fetches all posts and their comments in just two queries instead of one query per post. This avoids the N+1 query problem and can dramatically improve application performance, especially when dealing with large datasets.