Is the Repository Pattern Dead?

Leader posted 3 min read

Is the Repository Pattern Dead?

Introduction

The repository pattern has been a cornerstone of enterprise .NET architecture for years. It promised clean separation between business logic and data access, testability, and maintainability. But with modern ORMs like Entity Framework Core, and new design trends like CQRS, many developers are asking:

Is the repository pattern still relevant, or is it finally dead?

  1. What Is the Repository Pattern?

The Repository pattern is a well-known design pattern that aims to separate the logic that retrieves data from the business logic that acts on the data.

"A Repository mediates between the domain and data mapping layers using a collection-like interface for accessing domain objects."— Martin Fowler, Patterns of Enterprise Application Architecture

In practice, this means using a class that acts like an in-memory collection of domain objects — hiding whether the data comes from SQL, a web service, or somewhere else:

public interface ICustomerRepository
{
    Task<Customer> GetByIdAsync(Guid id);
    Task AddAsync(Customer customer);
}

Originally, this was valuable when ORMs weren’t mature and data access logic was verbose and database-specific.

  1. Why People Say It’s Dead

✅ EF Core Is Already a Repository

DbContext and DbSet provide the core functionality repositories offer: querying, adding, removing, and tracking entities.

❌ Boilerplate Hell

Most custom repositories end up duplicating what EF already provides:

public Task<Customer> GetByIdAsync(Guid id) => _context.Customers.FindAsync(id);

...which is not value-added abstraction.

Over-Abstraction Hurts

You lose direct access to EF Core's powerful features like:

  • .Include() for eager loading

  • .AsNoTracking() for read-only queries

  • Raw SQL with .FromSqlRaw()

However, patterns like Ardalis.Specification allow you to retain advanced EF Core features such as eager loading via .Include(), while still keeping your repository clean and decoupled. Specifications can express query logic clearly, including filters, includes, and sorting.

“Switching databases” is not a strong reason anymore

A common argument for using repositories is to make it easier to swap out databases (e.g., from SQL Server to PostgreSQL). But with Entity Framework Core, your application already depends on an abstraction — EF itself. Changing providers typically involves minimal changes to the DbContext configuration and nothing in your business logic. Adding another repository layer just to enable “swap-ability” is usually over-engineering.

  1. When the Repository Pattern Still Makes Sense

Despite the criticism, there are valid scenarios where repositories shine:

Domain-Driven Design (DDD) with rich aggregates and business rules

Abstracting external data sources (SQL + API + NoSQL)

Clear boundaries in microservices

NuGet/Repo Suggestions:

Ardalis.Specification: A clean implementation of the Specification Pattern that works great with EF Core.

Ardalis.CleanArchitecture: A full solution template with proper use of repositories and separation of concerns.

Refit: For when your "repository" is actually calling an external API.

EFCore.BulkExtensions: If you do stay close to DbContext, this helps with batch operations and performance.

  1. Modern Alternatives

Rather than force-fitting repositories, modern .NET developers are adopting:

CQRS + MediatR: Commands and queries are separated cleanly.

MediatR: Lightweight in-process messaging.

Query Object Pattern: Encapsulates complex queries into reusable classes.

Minimal APIs + DbContext injection (in .NET 6+): Simple, fast, and testable.

  1. Pragmatic Verdict

So, is the repository pattern dead? Not quite.

It's just no longer mandatory.

Use it when it adds value — such as enforcing boundaries, abstracting external sources, or aligning with your team's architecture. But don’t blindly wrap EF Core unless there’s a real reason.

Conclusion

The repository pattern isn’t dead — it’s evolved. In modern .NET, we have better tools, smarter defaults, and community-tested patterns like Ardalis.Specification that give you structure only when you need it.

Choose the right tool for your context. That’s real architecture.

References

Martin Fowler – Repository Pattern

Steve Smith – Ardalis.Specification GitHub

Steve Smith – Clean Architecture Template

Jeremy Bogard – MediatR GitHub

EFCore Bulk Extensions – GitHub Repository

Refit – GitHub Repository

If you read this far, tweet to the author to show them you care. Tweet a Thanks

More Posts

The Proxy Pattern: A Software Developer’s Essential Tool

Hussein Mahdi - Apr 25

Saga Pattern — an Introduction

Raj Kundalia - Aug 17

Reliable Messaging in .NET: Domain Events and the Outbox Pattern with EF Core Interceptors

Spyros - Oct 13

Clean React code pattern with the useImperativeHandle hook

Tony Edgal - May 20

Understanding the Observer Pattern in C# with IObservable and IObserver

Spyros - Mar 11
chevron_left