Which DI Lifetime to Use for DbContext?
If you’ve worked with Entity Framework Core, you’ve probably seen the classic interview question:
“What lifetime should you use for DbContext — Scoped, Transient, or Singleton?”
The correct answer is Scoped, but understanding why is what separates a junior developer from a senior engineer.
This guide explains the reasoning, the internals, and real-world scenarios so you can answer confidently in interviews and write safer, more scalable applications.
What Is DbContext?
DbContext represents a unit of work and a session with the database.
It:
- Tracks changes
- Manages entity states
- Handles database connections
- Executes queries
- Saves changes
Because it tracks state, its lifetime matters.
The Three DI Lifetimes in .NET
Before choosing the right one, here’s a quick refresher:
Transient
A new instance every time it’s requested.
Scoped
One instance per HTTP request.
Singleton
One instance for the entire application lifetime.
Why DbContext Should Be Scoped
✔️ 1. DbContext is not thread-safe
ASP.NET Core handles multiple requests concurrently.
If you use a Singleton DbContext, multiple threads will share the same instance.
This leads to:
- Race conditions
- Corrupted state
- Random exceptions
- Broken change tracking
✔️ 2. Scoped matches the unit-of-work pattern
Each HTTP request represents a business operation.
Examples:
- Creating an order
- Updating a profile
- Processing a payment
A scoped DbContext ensures:
- One context per operation
- One transaction per request
- Clean change tracking
- Predictable behavior
✔️ 3. Scoped ensures proper connection management
DbContext opens and closes connections efficiently within the request scope.
Why NOT Transient?
Transient creates a new DbContext every time it’s injected.
This causes:
❌ Multiple DbContexts in the same request
You may accidentally:
- Query with one context
- Save with another
- Lose change tracking
- Break transactions
❌ Hard-to-debug inconsistencies
Different DbContexts don’t share state.
Why NOT Singleton?
Singleton is the worst possible choice.
❌ DbContext is not thread-safe
Multiple requests → shared instance → chaos.
❌ Memory leaks
The context keeps tracking more and more entities.
❌ Stale data
Long-lived DbContexts cache query results.
❌ Broken transactions
A single DbContext cannot manage multiple concurrent operations.
Real‑World Scenarios
Scenario 1: Web API request
User updates their profile.
- One request
- One DbContext
- One transaction
Use Scoped
Scenario 2: Background service
A hosted service processes messages from a queue.
Each message should have its own DbContext.
using var scope = _serviceProvider.CreateScope();
var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();
Use Scoped inside a created scope
Scenario 3: Console app
Short-lived operations.
Transient or Scoped both work, but Scoped is still preferred for consistency.
How to Register DbContext Correctly
services.AddDbContext<AppDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("Default")));
This registers DbContext as Scoped by default.
Interview‑Ready Summary
- DbContext should be Scoped
- DbContext is not thread-safe
- Scoped aligns with unit-of-work
- Singleton causes race conditions and memory leaks
- Transient causes multiple contexts per request
A clean, senior-level answer:
“DbContext should be registered as Scoped because it represents a unit of work per request, is not thread-safe, and must not be shared across concurrent operations. Transient creates too many contexts, and Singleton causes concurrency issues and stale tracking.”
Top comments (0)