Still think EF Core setup takes hours? Give me 10 minutes – you’ll add packages, create a database, run a migration, and read data with one simple query.
What you’ll get
By the end, you will:
- create a clean .NET console app (no web project needed),
- install the right EF Core packages fast,
- generate your first migration and update the database,
- seed a bit of data, and
- run a real query with LINQ.
I’ll use SQLite so you don’t need a server. You can switch to SQL Server / PostgreSQL / MySQL in one minute – I’ll show the mapping.
Tested with .NET 8. Works the same for .NET 7+.
Prerequisites
- .NET SDK 8+ (
dotnet --version) - Any editor (VS Code, Visual Studio, Rider)
- Command line access
If dotnet works, you’re good.
Quick flow (high level)
new console app → add EF Core packages → create model & DbContext → add migration → update database → queryKeep this in mind as a checklist. We’ll go through each step.
Step 0 – Pick a provider (SQLite first)
For a first run, SQLite is perfect: a single file app.db, no server install.
Provider to package map
| Database | Provider package | Connection string sample |
|---|---|---|
| SQLite | Microsoft.EntityFrameworkCore.Sqlite | Data Source=app.db |
| SQL Server | Microsoft.EntityFrameworkCore.SqlServer | Server=.;Database=EfCoreQuickStart;Trusted_Connection=True;TrustServerCertificate=True |
| PostgreSQL | Npgsql.EntityFrameworkCore.PostgreSQL | Host=localhost;Database=efcore;Username=postgres;Password=postgres |
| MySQL | Pomelo.EntityFrameworkCore.MySql | Server=localhost;Database=efcore;User=root;Password=pass |
We’ll stick with SQLite in code samples, then I’ll show how to swap.
Step 1 – Create a project
mkdir EfCoreQuickStart
cd EfCoreQuickStart
dotnet new console -n EfCoreQuickStart
cd EfCoreQuickStartYou now have Program.cs and a .csproj.
Step 2 – Install EF Core packages
We need three things:
- a provider (SQLite here),
- design package (for migrations),
dotnet-efglobal tool.
# Provider
dotnet add package Microsoft.EntityFrameworkCore.Sqlite
# Design-time helpers for migrations
dotnet add package Microsoft.EntityFrameworkCore.Design
# CLI for migrations
dotnet tool install --global dotnet-ef
# (If already installed)
# dotnet tool update --global dotnet-efIf you use Visual Studio’s Package Manager Console instead:
Install-Package Microsoft.EntityFrameworkCore.Sqlite
Install-Package Microsoft.EntityFrameworkCore.DesignStep 3 – Add a model and a DbContext
Create a folder and two classes.
Models/Todo.cs
namespace EfCoreQuickStart.Models;
public class Todo
{
public int Id { get; set; }
public string Title { get; set; } = string.Empty;
public bool IsDone { get; set; }
public DateTime CreatedAtUtc { get; set; } = DateTime.UtcNow;
}Data/AppDbContext.cs
using EfCoreQuickStart.Models;
using Microsoft.EntityFrameworkCore;
namespace EfCoreQuickStart.Data;
public class AppDbContext : DbContext
{
public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { }
public DbSet<Todo> Todos => Set<Todo>();
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Todo>()
.Property(x => x.Title)
.HasMaxLength(200);
}
}Why the
OnModelCreatingbit? It shows how to add simple rules (like max length) without attributes. Either approach is fine.
Step 4 – Make migrations work in a console app
The EF tools must be able to create your DbContext at design time. In web apps, they use the host builder. In a console app, the simplest approach is to provide a small factory.
Data/AppDbContextFactory.cs
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Design;
namespace EfCoreQuickStart.Data;
public class AppDbContextFactory : IDesignTimeDbContextFactory<AppDbContext>
{
public AppDbContext CreateDbContext(string[] args)
{
var options = new DbContextOptionsBuilder<AppDbContext>()
.UseSqlite("Data Source=app.db")
.Options;
return new AppDbContext(options);
}
}This tiny class removes the most common setup error: “Unable to create an object of type ‘AppDbContext’.”
Step 5 – Add the first migration
dotnet ef migrations add InitialCreateEF creates a Migrations folder with a timestamped migration and a ModelSnapshot. Open the migration file to see the generated schema.
Step 6 – Create (or update) the database
dotnet ef database updateA file app.db appears in your project directory. That’s your SQLite database with a Todos table.
Step 7 – Write a tiny app to seed and query
Replace your Program.cs with the snippet below. It ensures the database is migrated, seeds two records on an empty DB, and prints incomplete tasks.
Program.cs
using EfCoreQuickStart.Data;
using EfCoreQuickStart.Models;
using Microsoft.EntityFrameworkCore;
// Build a context the same way as design-time
using var db = new AppDbContextFactory().CreateDbContext(args);
// Apply any pending migrations at runtime (handy for demos/tools)
db.Database.Migrate();
// Seed once
if (!await db.Todos.AnyAsync())
{
db.AddRange(
new Todo { Title = "Install EF Core" },
new Todo { Title = "Run first query" }
);
await db.SaveChangesAsync();
}
// Query: grab all open items, newest first
var open = await db.Todos
.Where(t => !t.IsDone)
.OrderByDescending(t => t.CreatedAtUtc)
.ToListAsync();
Console.WriteLine("Open TODOs:");
foreach (var t in open)
{
Console.WriteLine($"#{t.Id}: {t.Title} (created {t.CreatedAtUtc:O})");
}Run it:
dotnet runExpected output
Open TODOs:
#2: Run first query (created 2025-01-02T12:34:56.789Z)
#1: Install EF Core (created 2025-01-02T12:34:56.123Z)You’ve just installed EF Core, created a DB, and queried data. Nice.
Switch to another database (1-minute swap)
Keep your code. Change the provider package, factory, and connection string.
SQL Server
dotnet remove package Microsoft.EntityFrameworkCore.Sqlite
dotnet add package Microsoft.EntityFrameworkCore.SqlServerData/AppDbContextFactory.cs (change only the Use... line)
.UseSqlServer("Server=.;Database=EfCoreQuickStart;Trusted_Connection=True;TrustServerCertificate=True")Then:
dotnet ef database updatePostgreSQL
dotnet remove package Microsoft.EntityFrameworkCore.Sqlite
dotnet add package Npgsql.EntityFrameworkCore.PostgreSQLFactory:
.UseNpgsql("Host=localhost;Database=efcore;Username=postgres;Password=postgres")MySQL (Pomelo)
dotnet remove package Microsoft.EntityFrameworkCore.Sqlite
dotnet add package Pomelo.EntityFrameworkCore.MySqlFactory:
.UseMySql(
"Server=localhost;Database=efcore;User=root;Password=pass",
ServerVersion.AutoDetect("Server=localhost;Database=efcore;User=root;Password=pass"))Tip: for PostgreSQL or MySQL in dev, run a quick container:
docker run -e POSTGRES_PASSWORD=postgres -p 5432:5432 -d postgres:16docker run -e MYSQL_ROOT_PASSWORD=pass -p 3306:3306 -d mysql:8
Run dotnet ef database update again to create the schema in the new database.
Common errors and fast fixes
- “The term ‘dotnet-ef’ is not recognized” – install or update the tool:
dotnet tool install --global dotnet-ef
dotnet tool update --global dotnet-ef- “Unable to create an object of type ‘AppDbContext’.” – add the factory (shown above). EF needs a way to build the context at design time.
- “No database provider has been configured” – you forgot
.UseSqlite(...)(or.UseSqlServer(...)) when building options. - Wrong startup / project – when solutions have multiple projects, pass explicit paths:
dotnet ef migrations add InitialCreate --project src/Data --startup-project src/App- Revert a bad migration – last one only:
dotnet ef migrations removeOr rollback DB state:
dotnet ef database update PreviousMigrationName- Switch from EnsureCreated() – for real apps use migrations, not
EnsureCreated(). It skips schema history and will bite later.
Bonus: quick tests with the InMemory provider
For unit tests, you can skip a real database:
dotnet add package Microsoft.EntityFrameworkCore.InMemoryvar options = new DbContextOptionsBuilder<AppDbContext>()
.UseInMemoryDatabase("test-db")
.Options;
using var db = new AppDbContext(options);Don’t run migrations against InMemory. It’s for tests only.
Visual cheat sheet
1) dotnet new console
2) dotnet add package (provider + design)
3) add model + DbContext
4) factory for design-time DbContext
5) dotnet ef migrations add InitialCreate
6) dotnet ef database update
7) dotnet run (seed + query)Print and keep near your keyboard. Saves time.
Useful add-ons (when you’re ready)
- Logging SQL
var options = new DbContextOptionsBuilder<AppDbContext>()
.UseSqlite("Data Source=app.db")
.EnableSensitiveDataLogging() // dev only
.LogTo(Console.WriteLine)
.Options;- Connection string in user-secrets (dev)
dotnet user-secrets init
dotnet user-secrets set ConnectionStrings:Default "Data Source=app.db"Then read it and pass to UseSqlite(secretValue).
- Automatic migrations on start (tools/demos) – we already used
db.Database.Migrate()inProgram.cs. For web apps, place it in a scoped startup block.
FAQ: EF Core install and first steps
No. A console app is fine. EF Core is not tied to ASP.NET.
Provider + Microsoft.EntityFrameworkCore.Design. The design package gives migrations. The CLI tool dotnet-ef is global.
For quick starts, inline is okay. For real apps, use configuration (appsettings, user-secrets, env vars).
EnsureCreated() works for throwaway demos. Prefer migrations for anything that lives longer than a day.
Add a migration after changing the model. EF generates RenameColumn/RenameTable or Add/Drop as needed. Review the script before applying.
Enable LogTo(Console.WriteLine) and (optionally) EnableSensitiveDataLogging() in dev.
Yes. Place AppDbContext in a library and point --project / --startup-project properly when running tools.
Conclusion: EF Core in minutes, not days
You now have a repeatable setup: new project, add two packages, add a model + context, run a migration, run a query. That’s the core loop for any EF Core app. Next time you need persistence in a quick tool or a service, copy this small template and you’ll move faster.
Got a snag, or want a version with ASP.NET and dependency injection wired in? Drop a comment with your case – I’ll add a follow‑up sample.
