What is DbContext?

In Entity Framework Core, DbContext acts as a bridge between your application and the database. It handles querying, saving, and managing entities. But when your app scales or gets more complex, you may run into scenarios where using a single DbContext isn’t enough, and that’s where multi-DbContext design shines.

What is Multi-DbContext?

Multi-DbContext means creating and using more than one DbContext in your application. Instead of having a single context for the entire database, we split our data access into multiple smaller DbContext classes, each handling a specific module, feature, or part of the data.

For example, I used separate contexts like AuthorDbContext and PostDbContext for different parts of my project. This way, each context is responsible only for what it needs.

This approach is helpful when your app becomes large and you want better control over performance, responsibilities, or need to avoid thread-safety issues in asynchronous methods.

Why I Chose Multiple DbContexts in My Scenario:

Problem: Concurrency Exceptions in Asynchronous Code

Entity Framework Core’s DbContext is not thread-safe, which means you cannot perform multiple database operations in parallel using the same instance.

In my initial implementation, I tried to fetch data for both the Author and Post entities simultaneously using a single DbContext:

builder.Services.AddDbContext<SingleDbContext>(options =>
    options.UseNpgsql(builder.Configuration.GetConnectionString("DefaultConnection")));

It worked fine… until I hit a real-world problem.

public async Task TriggerConcurrencyError()
{
    var taskOne = _singleDbContext.Author.FirstOrDefaultAsync();
    var taskTwo = _singleDbContext.Post.FirstOrDefaultAsync();

    await Task.WhenAll(taskOne, taskTwo);
}

This looks fine at first, but it throws this error:

A second operation was started on this context instance before a previous operation was completed.

Why?

Because the Entity Framework DbContext isn’t thread-safe. When two operations are triggered at the same time on the same context instance (like above), it fails.

What Did I Do?

I split the logic into two separate contexts.

builder.Services.AddDbContext<AuthorDbContext>(options =>
    options.UseNpgsql(builder.Configuration.GetConnectionString("DefaultConnection")));

builder.Services.AddDbContext<PostDbContext>(options =>
    options.UseNpgsql(builder.Configuration.GetConnectionString("DefaultConnection")));

Then my async call became:

public async Task FixedVersion()
{
    var taskOne = _authorDbContext.Author.FirstOrDefaultAsync();
    var taskTwo = _postDbContext.Post.FirstOrDefaultAsync();

    await Task.WhenAll(taskOne, taskTwo);
}

This fixed the issue completely because now each async operation uses a separate DbContext. No sharing. No conflict.

You can access the complete source code on GitHub: Repository

Pros of Using Multi-DbContext

Cons of Using Multi-DbContext

Conclusion

That’s how and why I ended up using multiple DbContexts in my app. It’s not the only solution, but in my case, it gave me better control, helped avoid concurrency issues, and kept my architecture clean.