
Tldr
Transient objects are always different; a new instance is provided to every controller and every service. Scoped objects are the same within a request, but different across different requests. Singleton objects are the same for every object and every request.
Memory trick
T = Tiny/stateless, T t = new();S = Scope/request, passing a particular object from methodA to methodBS = Shared/application, global
builder.Services.AddTransient<ITransientService, OperationService>();
builder.Services.AddScoped<IScopedService, OperationService>();
builder.Services.AddSingleton<ISingletonService, OperationService>();1. Transient Lifetime (AddTransient)
-
Behavior:
- A brand-new instance is created every single time it is requested.
-
Real-World Scenario:
- A stateless utility or calculation engine, such as a password hasher or an automated text formatting parser.
-
Why Use It:
- Prevents state leakage. Because the service holds no internal state, giving every consumer a fresh instance completely eliminates multi-threading and concurrency bugs.
Use For Lightweight, stateless services that perform short-lived operations and do not need to share data with other components during an operation.
Eg : calculators, formatters, validators, mappers, and lightweight transformation services.
2. Scoped Lifetime (AddScoped)
-
Behavior:
- A single instance is created once per client request (one instance per incoming HTTP request in web apps).
-
Real-World Scenario:
- Entity Framework Core
DbContextinteracting with a repository pattern.
- Entity Framework Core
-
Why Use It:
- Ensures that everything handling a single HTTP request shares the same Unit of Work without risking cross-request data corruption or tracking conflicts.
Where to Use
Web API controllers, unit-of-work classes, repositories, and business logic layers that interact with databases or maintain state for the duration of a single user transaction.
3. Singleton Lifetime (AddSingleton)
-
Behavior:
- A single instance is created the first time it is requested and persists across the entire application lifecycle.
-
Real-World Scenario:
- An in-memory caching service (
IMemoryCache) or an application-wide configuration manager.
- An in-memory caching service (
-
Why Use It:
- Maximizes performance and reduces memory overhead by preventing repetitive object creation for data that rarely changes and is thread-safe.
Where to Use
Background worker services (
IHostedService), caching layers, configuration options, and connection managers shared globally across all users and requests.
Watch out for Captive Dependencies Never inject a Transient or Scoped service directly into a Singleton service. Because the Singleton lives forever, it will "capture" the short-lived dependency, causing it to behave like a Singleton and potentially causing memory leaks or multi-threading bugs.
The rules to remember
DbContext → Scoped
Request-specific state → Scoped
Stateless lightweight → Transient
Shared immutable state → Singleton
Mutable Singleton → Check thread safety
Singleton → Scoped → ❌ Avoid
ECS Singleton → Per task/process
Lambda Singleton → Per execution environment