Collections in Laravel: Operations, Methods, and Best Practices

Video thumbnail

Laravel collections are nothing new to anyone who has worked even minimally with the framework. In fact, we use them almost without realizing it every time we retrieve data from the database with Eloquent. In my case, I truly began to appreciate them when I stopped treating results as simple arrays and started chaining operations directly on them.

In this article, I am going to focus on collection operations in Laravel, explaining what they are, how they are created, which methods I use most in my day-to-day work, and which best practices are worth following to avoid performance issues or unnecessarily complex code.

What are Laravel collections and why use them

Laravel collections are, basically, PHP arrays on steroids. Internally, they are implemented using the class:

Illuminate\Support\Collection

But the important thing is not the class itself, but everything it allows us to do. A collection is a wrapper over a traditional array that adds a huge number of methods to filter, transform, group, sort, and reduce data in a much more expressive way.

In real projects, working with collections has allowed me to reduce foreach loops, eliminate temporary variables, and make the logic much clearer. Instead of saying how to traverse the data, we move on to saying what we want to do with it.

Collections vs arrays in PHP

Although collections are internally based on arrays, the practical difference is enormous:

Arrays require manual loops, conditions, and more code.

Collections allow for chaining methods and writing declarative code.

For example, filtering adult users with arrays involves traversing the entire set. With collections, a well-expressed filter() is enough. Additionally, most collection methods do not modify the original set but return a new collection instead, which reduces side effects and hard-to-detect errors.

How to create collections in Laravel

Collections returned by Eloquent

Collections are nothing new; up until this point, we have used collections in previous developments. Every time we had a list as a database response to create a table in a view, collections were used.

The most common use of collections occurs when working with Eloquent. Every time we execute a query with get(), Laravel returns a collection:

Category::all();

And this is very easy to see if you print the previous result in debug mode or Tinker:

dd(Category::all());

Illuminate\Database\Eloquent\Collection 
  #items: array:N
}

Laravel collections are an essential tool for managing lists, but we can also create our own collections as we will see in this section.

Collections are nothing more than PHP arrays but with vitamins; this means they are the same arrays but with a set of additional functionalities to make them easier and more user-friendly under the class:

Illuminate\Support\Collection 

Creating collections manually with collect()

In addition to the collections that come from Eloquent, we can create our own from PHP arrays:

Although this class is not only used internally, we can also use it manually; that is, we can create a collection from an array in PHP:

$personas = [
        ["nombre" => "usuario 1", "edad" => 50],
        ["nombre" => "usuario 2", "edad" => 70],
        ["nombre" => "usuario 3", "edad" => 10],
];

Basic operations with collections

This is where collections start to make a real difference compared to arrays.

map()

map() transforms each element of the collection and returns a new collection:

To do this, we have several ways:

use Illuminate\Support\Facades\Collection;
***
$collection1 = collect($personas);
//dd($collection1);
$collection2 = new Collection($personas);
//dd($collection2);
$collection3 = Collection::make($personas);
//dd($collection3);

filter() and reject()

filter() returns only the elements that meet a condition.

With the collection, it is now possible to use all kinds of built-in collection methods, such as the filter method:

$collection2->filter(function($value,$key){
    return $value['edad'] > 17;
})

reject() does exactly the opposite: it removes the elements that meet the condition.

Which returns a collection of those elements that meet the condition; in this example, where the age is greater than 17:

Illuminate\Support\Collection {#5178
    all: [
      [
        "nombre" => "usuario 1",
        "edad" => 50,
      ],
      [
        "nombre" => "usuario 2",
        "edad" => 70,
      ],
    ],
  }

sum(), avg(), min(), max()

One of the great strengths of collections is the ease of performing aggregate operations.

Since the filter() method returns a collection, we can queue other collection operations, such as summing:

$collection2->filter(function($value,$key){
    return $value['edad'] > 17;
})->sum('edad'));

Which in this case, does not return a collection, but an integer:

120

This type of chaining (filter()->sum()) is something I use a lot in real code.

pluck(), keys() and values()

pluck() allows you to extract a specific property from all elements:

$nombres = $collection->pluck('nombre');

It is also very common to work with the keys and values of a collection using keys() and values(), especially when dealing with collections with string-type indices.

Chained operations in collections

One of the greatest advantages of collections is that most of their methods return another collection, allowing them to be chained.

Chaining filters and transformations

For example:

$resultado = $collection
   ->filter(fn ($p) => $p['edad'] > 17)
   ->map(fn ($p) => $p['edad'])
   ->sort();

This type of code is very readable: you can understand at a glance what is happening without needing to follow internal loops.

Real-world chaining examples

In one of my most common cases, I use collections to clean results before sending them to a view:

$users = User::all()
   ->filter->isActive()
   ->sortBy('name')
   ->pluck('email');

This is also where Higher Order Messages come into play, which we will talk about later.

Intermediate and advanced operations

groupBy(), chunk() and partition()

groupBy() allows you to group data easily:

$grouped = $collection->groupBy('edad');

chunk() is especially useful when working with large collections:

$collection->chunk(50)->each(function ($group) {
  // process groups of 50 elements
});

partition() divides a collection into two based on a condition, which is very practical for separating data into two logical blocks.

intersect(), merge() and concat()

Another interesting method is the intersection method which removes any value from the original collection that is not present in the provided array:

$collection = collect(['Desk', 'Sofa', 'Chair']); 
$intersect = $collection->intersect(['Desk']);

And it returns:

$collection->intersect(['Desk'])                                                                                               
= Illuminate\Support\Collection {#5118
    all: [
      "Desk",
    ],
  }

I have found this method particularly useful for validating lists against allowed values.

Higher Order Messages and Lazy Collections

Simplifying code with Higher Order Messages

Laravel allows for writing cleaner code using Higher Order Messages:

$users->each->markAsActive();

This avoids repetitive anonymous functions and makes the code much more expressive.

Lazy Collections and performance

When working with large volumes of data, loading everything into memory is not always a good idea. For these cases, Laravel offers LazyCollection.

In massive imports or reading large files, I have found that using lazy collections makes a huge difference in memory consumption.

Best practices when working with collections

When to use collections and when not to

Whenever you can, use collections for clarity and expressiveness. However, if you are working with massive datasets, evaluate whether the operation should be done in the database instead of in PHP.

Collections vs database operations

A common mistake is doing this:

User::where('active', 1)->get()->sortBy('created_at');

When it would be much more efficient:

User::where('active', 1)->orderBy('created_at')->get();

This kind of detail makes the difference in applications with many records.

Common mistakes and practical advice

  • Chaining too many methods without breaking up the code.
  • Using map() for side effects instead of each().
  • Not taking advantage of existing methods and reinventing the wheel.
  • Processing in PHP what should be done in SQL.

Frequently asked questions about Laravel collections

  • What are Laravel collections?
    • They are array-based structures that provide advanced methods to manipulate data expressively.
  • What is the difference between an array and a collection?
    • Collections allow for method chaining, improve readability, and reduce common errors.
  • When to use LazyCollection?
    • When working with large volumes of data and you want to reduce memory usage.
  • Can collections be extended?
    • Yes, through macros or by creating custom classes that extend Collection.

Conclusion

Laravel collections are one of the framework's most powerful tools. Well-used, they allow for writing cleaner, more maintainable, and expressive code. In my experience, mastering collection operations marks a before and after in the way you work with data in Laravel.

If you adopt a functional approach, take advantage of method chaining, and pay attention to performance, collections will become a key piece of your daily workflow.

These methods are specific to collections; you can check the official documentation to learn about the enormous number of methods available only when using collections that do not exist with arrays at:

https://laravel.com/docs/master/collections

I agree to receive announcements of interest about this Blog.

Learn what collections are in Laravel, how to create and chain operations, key methods, practical examples, and performance best practices.

| 👤 Andrés Cruz

🇪🇸 En español