Program.cs vs. Startup.cs in ASP.NET Core: Best Practices 2026
Program.cs vs. Startup.cs
One of the first decisions you make when starting a new ASP.NET Core project is the structure of your application startup. The evolution from the traditional Startup.cs to the modern Program.cs has created confusion. Let's clear it up.
⚡ The Short Answer: For new projects, use Program.cs with the minimal hosting model. For existing projects using Startup.cs, there's no urgent need to rewrite. Focus on maintainability, not style.
The Evolution
The Traditional Approach: Startup.cs
In earlier versions of ASP.NET Core, the Startup class was the standard way to configure services and the request pipeline. It provided clear separation of concerns with two distinct methods:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
services.AddDbContext<ApplicationDbContext>();
// ... more service registrations
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseRouting();
app.UseAuthorization();
app.MapControllers();
}
}
The Modern Approach: Program.cs
With .NET 6 and later, the minimal hosting model brought everything into a single Program.cs file. This approach uses top-level statements and reduces boilerplate code.
var builder = WebApplication.CreateBuilder(args);
// Configure services
builder.Services.AddControllersWithViews();
builder.Services.AddDbContext<ApplicationDbContext>();
var app = builder.Build();
// Configure pipeline
if (app.Environment.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseRouting();
app.UseAuthorization();
app.MapControllers();
app.Run();
Which One Should You Use?
| Feature | Program.cs | Startup.cs |
|---|---|---|
| Code Organization | Single file (can be modularized) | Two distinct methods |
| Boilerplate | Minimal | More verbose |
| Extension Methods | Easy to add | Easy to add |
| Testing | Requires pattern | Well-established |
| Migration Effort | Manual | None (existing projects) |
💡 Pro Tip: The choice isn't binary. You can use extension methods to keep your Program.cs clean and organized, mimicking the separation you'd get from Startup.cs.
Best Practices for Program.cs
Use Extension Methods for Organization
// Program.cs
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddApplicationServices();
builder.Services.AddDatabaseServices(builder.Configuration);
builder.Services.AddSecurityServices();
var app = builder.Build();
app.UseSecurityHeaders();
app.UseApplicationPipelines();
app.Run();
// ServiceExtensions.cs
public static class ServiceExtensions
{
public static IServiceCollection AddApplicationServices(this IServiceCollection services)
{
services.AddControllersWithViews();
services.AddRazorPages();
return services;
}
public static IServiceCollection AddDatabaseServices(this IServiceCollection services, IConfiguration configuration)
{
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(configuration.GetConnectionString("DefaultConnection")));
return services;
}
}
When to Keep Startup.cs
- Existing Projects: If your application is already using
Startup.csand working well, there's no need to rewrite it - Complex Configuration: Applications with extensive configuration logic can benefit from the clear separation of
Startup.cs - Testing Requirements: The
Startuppattern makes integration testing easier with custom test startups - Team Familiarity: If your team is more comfortable with the traditional pattern, stick with it
Migration Strategy
If you're considering migrating an existing project from Startup.cs to the minimal hosting model, follow these steps:
- Create a new Program.cs with the minimal hosting model
- Copy your ConfigureServices logic to the builder.Services section
- Copy your Configure logic to the app configuration section
- Remove the Startup.cs file from your project
- Test thoroughly to ensure all functionality works as expected
✅ Recommendation: Migrate when you're already making significant changes to your project. Avoid migrating just for the sake of it.
Conclusion
📌 Key Takeaway: The choice between Program.cs and Startup.cs is about organization, not capability. Both approaches are fully supported and can create maintainable applications. Choose the one that works best for your team and project context.