ASP.NET Core: multiple contexts and databases

How to split a model across multiple DbContext instances and databases in ASP.NET Core with EF Core and Identity: configuration, migrations, DI, usage example, and best practices for scaling and organising logs.

Mateusz Kopta

Introduction

The first version of an application usually comes together smoothly: we have the documentation, configure environments, deploy and… the rising user growth chart is satisfying. Until the database starts growing exponentially and slows down the entire platform.

The source of the problem? A single, monolithic database stores both domain data and operational logs. The solution: split responsibilities across multiple contexts and databases while keeping a consistent model in the code.

Goal and assumptions

- Split data into smaller, independent sets - Have a simple way to handle multiple DbContext instances from within the application - Maintain a straightforward migration process in EF Core

Technology stack

ASP.NET Core 2.x, Entity Framework Core (Code First), and Identity.

Sample application model

Let us assume a simple forum. Users create threads containing posts. Additionally, we record user activity as logs.

- Domain data: Users, Threads, Posts - Logs: UserActionLog

Two contexts, two databases

The first context handles domain data and inherits from IdentityDbContext, which allows it to link users with Thread and Post. The second context, based on DbContext, stores only user log entries.

- DomainDbContext: Identity + Threads + Posts - ActionLogDbContext: UserActionLogs

Benefits:

- Clear responsibility boundaries and easier maintenance - Independent lifecycles and data retention strategies - The ability to scale and tune each database separately

Factories and context aggregator

To conveniently obtain the appropriate DbContext, we define a factory interface and implementations for each context. We register them in ASP.NET Core DI. Finally, we create a lightweight aggregator that wraps the factories and returns the requested context by key or type.

- IDbContextFactory: contract for creating DbContext instances - ActionLogDbContextFactory and DomainDbContextFactory: implementations registered in DI - DbContexts: an aggregating object exposing contexts through an indexer

This allows us to retrieve the correct data source anywhere in the application without duplicating configuration.

Registration in Startup

In ConfigureServices, we register both contexts with separate connection strings from appsettings.json, as well as the factories and the DbContexts aggregator. The web host uses the Startup class when launching the application.

- Example connection string names: DomainDataDbConnection and ActionLogDataDbConnection

Migrations for multiple contexts

EF Core supports multiple contexts in migrations using the -Context parameter and separate migration directories. We run two series of Add-Migration and Update-Database commands, one for each context, also specifying the startup project via -Startup.

Example Add-Migration commands:

Add-Migration Initial -Context DomainDbContext -OutputDir Migrations/DomainDbContextMigrations -Startup MultipleContextsApp.Web

Add-Migration Initial -Context ActionLogDbContext -OutputDir Migrations/ActionLogDbContextMigrations -Startup MultipleContextsApp.Web

Then update the databases:

Update-Database -Context DomainDbContext -Startup MultipleContextsApp.Web

Update-Database -Context ActionLogDbContext -Startup MultipleContextsApp.Web

As a result, we get two independent migration histories and a clear structure in the model layer.

Usage in the application

We inject DbContexts (the aggregator) wherever we need data access: in controllers, handlers or—preferably—in the data access layer (DAL). The DAL then exposes an interface to higher layers.

Example use in a controller:

- The GetActions method retrieves entries from ActionLogDbContext using the ActionLogDataDbConnection connection - The GetThreads method retrieves threads from DomainDbContext using the DomainDataDbConnection connection

Best practices

- Separate data with different dynamics and retention requirements (e.g. logs vs business data) - Provide each context with its own migration directory - Monitor connections and limits, scaling databases independently - Hide data access details behind the DAL to maintain modularity

Summary

We have built a web application skeleton using multiple DbContext instances and databases. We now have a clear separation of responsibilities, simpler migrations, and the flexibility to scale. In larger projects, we inject the context aggregator into the DAL, which simplifies maintenance and further development.

Do you have questions or want to assess whether your database can handle traffic growth? Get in touch with us — we will prepare a free analysis.

Do you need technology support?

Let us talk about your project — from discovery to deployment.

Book a consultation

Would you like to know more?

Explore other articles or let’s discuss your project

All articles Let’s design your AI application
An unhandled error has occurred. Reload 🗙