Introduction
In ASP.NET Core, Dependency Injection (DI) is a built-in feature that helps manage object creation and lifetime. When you register services in the DI container, you often see three common methods: AddTransient, AddScoped, and AddSingleton.
Understanding the difference between AddTransient vs AddScoped vs AddSingleton is very important for building scalable, high-performance, and bug-free applications. Choosing the wrong lifetime can lead to memory issues, unexpected behavior, or performance problems.
In this article, we will explain each lifetime in simple words, compare them clearly, and show real-world examples so you can confidently decide which one to use.
What is Dependency Injection in ASP.NET Core?
Dependency Injection is a design pattern used to achieve loose coupling between classes.
Instead of creating objects manually, the framework provides them when needed.
Example:
public interface IMessageService
{
void Send(string message);
}
public class EmailService : IMessageService
{
public void Send(string message)
{
Console.WriteLine($"Email Sent: {message}");
}
}
Registering in DI container:
builder.Services.AddTransient<IMessageService, EmailService>();
What is AddTransient?
AddTransient creates a new instance of a service every time it is requested.
Key Points of AddTransient
New object is created every time
Lightweight and short-lived
No shared state
Best for stateless services
Example of AddTransient
builder.Services.AddTransient<IMessageService, EmailService>();
If this service is injected into multiple places, each injection gets a new instance.
When to Use AddTransient
What is AddScoped?
AddScoped creates one instance per request.
In web applications, a "request" means a single HTTP request.
Key Points of AddScoped
Example of AddScoped
builder.Services.AddScoped<IMessageService, EmailService>();
All components within the same request share the same instance.
When to Use AddScoped
What is AddSingleton?
AddSingleton creates only one instance for the entire application lifetime.
Key Points of AddSingleton
Example of AddSingleton
builder.Services.AddSingleton<IMessageService, EmailService>();
All users and requests share the same instance.
When to Use AddSingleton
Difference Between AddTransient, AddScoped, and AddSingleton
| Feature | AddTransient | AddScoped | AddSingleton |
|---|
| Lifetime | New every time | Per request | Entire application |
| Instance Sharing | No | Within request | Across application |
| Memory Usage | Low per instance | Moderate | Lowest (single instance) |
| Thread Safety Required | No | No | Yes |
| Performance | Fast creation | Balanced | Best for reuse |
Visual Understanding
AddTransient → Always new instance
AddScoped → Same instance per request
AddSingleton → Same instance for entire app
Real-World Example
Imagine an e-commerce application:
AddTransient → Email sender service (no shared data)
AddScoped → Shopping cart service (per user request)
AddSingleton → Configuration service (shared globally)
Common Mistakes Developers Make
Using Singleton for services that depend on Scoped services
Not making Singleton services thread-safe
Overusing Transient leading to too many object creations
Misunderstanding request scope in APIs
Important Rule (Very Important)
Never inject a Scoped service into a Singleton.
This can cause runtime errors because Singleton lives longer than Scoped.
Best Practices
Use AddTransient for lightweight, stateless services
Use AddScoped for request-based logic
Use AddSingleton for shared, expensive services
Always consider thread safety
Advanced Tip
If you are unsure which lifetime to choose:
Summary
Understanding AddTransient vs AddScoped vs AddSingleton is essential for effective Dependency Injection in ASP.NET Core. Transient creates a new instance every time, Scoped creates one per request, and Singleton creates one for the entire application. Choosing the correct lifetime helps improve performance, maintainability, and scalability of your application.