.NET  

IEnumerable vs IQueryable in .NET

In .NET development, two familiar faces often pop up when working with LINQ: IEnumerable and IQueryable . They look similar, both let us loop through data, and both claim to help us fetch what we need.

But here's the reality: one is like downloading every email in our inbox and then searching for the one message we actually care about, while the other is like asking the mail server to send us only the specific email that matches our filter.

Knowing the difference is critical. Choose wrong, and our app may feel like it's stuck in a Monday morning traffic jam; choose right, and everything flows smoothly, just like that perfectly timed green light.

IEnumerable is best for in-memory iteration and filtering, while IQueryable is for querying remote data sources where the provider translates LINQ into SQL or another query language.

IEnum vs IQuery

IEnumerable

IEnumerable<T> is an interface in System.Collections.A generic that allows us to iterate over a collection of items using a foreach loop. It works on in-memory data like List<T>, Array, or Dictionary.

Think of it as a playlist downloaded on our phone :

  • All songs (data) are already there.

  • We just choose which songs to play (filter/process in memory).

Imagine we are building a Library Management System. We already have a list of books in memory (like after fetching them from a database or API). Now, we want to filter only the books that are published after 2020.

List<Book> books = new List<Book>
{
    new Book { Title = "C# Basics", Year = 2018 },
    new Book { Title = "Advanced C#", Year = 2021 },
    new Book { Title = "ASP.NET Core", Year = 2022 }
};

// IEnumerable works on in-memory data
IEnumerable<Book> recentBooks = books.Where(b => b.Year > 2020);

foreach (var book in recentBooks)
{
    Console.WriteLine(book.Title);
}

What happens here:

  • The filtering (b.Year > 2020) is done in memory because the data is already loaded in the list.

  • No SQL or database interaction here.

  • This is efficient when you already have the data in memory and just need to filter, loop, or process it.

Important Tips

  1. IEnumerable is best for in-memory data.

  2. Belongs to System.Collections & System.Collections.Generic namespaces.

  3. Supports forward-only iteration (cannot go backward).

  4. Queries are executed in memory, not on the database.

  5. Uses deferred execution until iterated with foreach or ToList().

  6. Suitable for small/medium datasets, not for huge ones.

  7. Works with LINQ (Where, Select, etc.), but processing happens locally.

  8. If data needs to be filtered in the DB → we should use IQueryable instead.

IQueryable

IQueryable <T> is an interface in the System.Linq namespace that allows us to query data from remote data sources (like databases, APIs, or external services).

  • It extends IEnumerable <T>. IQueryable → builds query (SQL at DB level) → returns IEnumerable results.

  • Queries are not executed immediately; instead, they are translated into an expression tree, which the provider (like Entity Framework) converts into the source's native query language (like SQL).

  • Filtering, sorting, and aggregations happen at the data source instead of in memory. Think of IQueryable as placing a food order at a restaurant — we ask for exactly what we want, and the chef (database) prepares and delivers only that.

"IQueryable<T> extends IEnumerable<T> so that it can inherit iteration capabilities. This way, after the query is executed at the data source, we can still enumerate the results in the same way as any in-memory collection. It also ensures LINQ operators work consistently across both in-memory (IEnumerable) and remote data sources (IQueryable)."

Imagine we are building a School Management System where millions of student records are stored in a SQL Server database. Now, we want to fetch only the students older than 18.

  
    using (var context = new SchoolDbContext())
{
    // Query is built but not executed yet
    IQueryable<Student> eligibleStudents = context.Students.Where(x => x.Age > 18);

    // Query executes here when iterated
    foreach (var student in eligibleStudents )
    {
        Console.WriteLine(student.Name);
    }
}
  

What happens here:

  • The query is translated into SQL like this:

  
    SELECT * FROM Students WHERE Age > 18;
  
  • Only the filtered data (students older than 18) is fetched from the database.

  • This is efficient because instead of pulling thousands of student records into memory, only the matching records are returned.

This is exactly how most web applications (like e-learning platforms, e-commerce sites, or HR systems) fetch only the relevant data from databases without overloading the application server.

Important Tips:

  1. IQueryable is in System.Linq and extends IEnumerable.

  2. Supports deferred execution, query is executed only when enumerated ( foreach , ToList() ).

  3. Used for remote data sources (databases, APIs).

  4. Filters, sorting, and aggregations are executed at the data source, not in memory.

  5. Efficient for large datasets (fetches only required data).

  6. Avoid calling .ToList() too early; it forces execution and loads everything into memory.

  7. Not all C# methods can be translated to SQL use only supported LINQ methods.

  8. Best choice when working with Entity Framework, LINQ-to-SQL, or OData APIs.

AspectIEnumerableIQueryable
ProcessLoads all records (e.g., 1 million students) into application memory first.Builds an expression tree that EF translates into SQL WHERE clause.
FilteringDone in C# / application memory after fetching all rows.Done in database before data is sent to the application.
Example (Age > 18)Load all students → Loop through in C# → Apply condition.EF generates SQL: SELECT * FROM Students WHERE Age > 18 → Only matching rows come.
Performance ImpactHigh memory usage, more CPU cycles, longer query times.Minimal memory usage, faster execution, less network load.
Best Use CaseWhen working with small, in-memory collections (e.g., arrays, lists).When working with remote data sources (e.g., SQL Server via EF, LINQ to SQL).

Conclusion

Both IEnumerable and IQueryable are powerful tools in .NET, but they solve different problems:

  • IEnumerable is like working with a shopping bag already in our hands, the items are already loaded (in memory), and we just sort, filter, or iterate through them. It shines when dealing with small/medium in-memory datasets.

  • IQueryable is like telling the store clerk what we need, they go fetch only those items for us (database does the heavy lifting). It's ideal when working with large datasets from remote sources like databases, because filtering, sorting, and aggregations happen before data is fetched.

In short:

  • Use IEnumerable when data is already in memory.

  • Use IQueryable when working with external data sources and performance matters.