# FluentMigrator: C# schema migrations for teams that do not want EF Core in the driver's seat

> FluentMigrator is a .NET migration framework in the Ruby on Rails Migrations tradition: schema changes live in C# classes, not loose SQL scripts. Here is how the migration classes, runner and version table fit together, plus where the framework stops helping.

**fluentmigrator/fluentmigrator** — Fluent migrations framework for .NET

- Repository: https://github.com/fluentmigrator/fluentmigrator
- Website: https://fluentmigrator.github.io
- Stars: 3,515 · Forks: 703
- Language: C#
- License: Apache-2.0
- Published: 2026-09-23 · Updated: 2026-09-23 · Language: en
- Canonical page: https://hysenlabs.com/projects/fluentmigrator-fluentmigrator

## The problem FluentMigrator solves: schema drift across developer, test and production databases

The README states the problem plainly: migrations are an alternative to creating lots of SQL scripts that have to be run manually by every developer involved. That sentence describes a real failure mode. A team keeps a folder of .sql files, one developer runs the first three on their local database, another runs a hand-edited fourth, and the test database ends up with a column that production does not have. Schema differences accumulate silently until a deployment fails.

FluentMigrator's answer is to move schema changes into C# classes that are checked into version control, the same way application code is. Each change is a class with an Up method and a Down method. The migration is compiled, reviewed and merged like any other code, and the same binary runs against every database the team owns. The intended audience is a .NET shop that wants schema evolution to follow the same pull request and CI path as the rest of the codebase.

The framework is not a database abstraction layer. It does not generate an object model from your schema, and nothing in the README suggests it manages queries at runtime. It creates and alters tables, columns, indexes and constraints, and it records which migrations have run. That narrower scope is the point.

## How the migration classes, runner and version table fit together

A migration is a class carrying the [Migration] attribute with a version number. Inside, the fluent API describes the change: creating a table and its columns, adding an index, altering a column type. The Down method describes the reverse. The README's framing is that these classes are checked into version control, so the history of the schema is readable in the same tool that shows the history of the application.

The runner is what actually applies them. It connects to a database, looks at the version table, compares the recorded versions with the migrations available in the assembly, and executes the missing ones in order. The version table is the state: it is how the runner knows a migration has already been applied and must not run again. That table is the single source of truth, and it is why two tools applying changes to the same schema is a problem rather than a convenience.

Because the migrations are ordinary C# in an assembly, the runner can be invoked from several places. The repository ships samples for an MSBuild task, a console migrator and a migrations assembly, which reflects the fact that different teams want to trigger migrations from different points in their pipeline. The same compiled migrations can be run by a developer from a shell, by a CI step, or by a deployment job, provided all of them point at the same database and the same version table.

The database support is broad and listed in the project's topics: SQL Server, PostgreSQL, MySQL, Oracle, DB2, Redshift and Snowflake. That breadth is a design commitment. The fluent API has to express changes that all of these engines can execute, and where an engine has a feature the others lack, the API either exposes it conditionally or leaves it to raw SQL.

## Installing FluentMigrator and running a first migration

The README points to NuGet as the release channel: packages are published to nuget.org, while CI builds live on Azure Artifacts. The documentation site at fluentmigrator.github.io is where the project keeps its guides. Installation is a package reference in a .NET project, and the runner packages are what let a host application or a build step apply migrations.

Migrations are written as C# classes. The repository's samples directory contains FluentMigrator.Example.Migrations, FluentMigrator.Example.Migrator and FluentMigrator.Example.MSBuild, which are the project's own examples of a migrations assembly, a console migrator and an MSBuild-driven run. Those sample projects are the place to copy the class structure and the runner invocation from, because the README itself does not print a migration class or a runner command line.

The check that matters after the first run is that the version table now contains the version you assigned, and that the table described in the Up method exists with the columns you declared. The runner reads that table on every subsequent run, so a missing or misconfigured version table shows up immediately as migrations being reapplied.

One practical detail from the release notes: v8.0.0 is labelled .NET 10 Support, and the 7.1.0 notes mention .NET 9 support. The framework tracks current .NET versions closely, which is good for new projects and a constraint for teams pinned to an older runtime. The changelog is the place to confirm which target frameworks a given release supports.

## Where FluentMigrator is the wrong tool

The framework's model is forward-and-reversible migrations recorded in a version table, and that model has edges. The README does not document rollback guarantees, and the Down method is only as good as what the author wrote there. A migration that drops a column in Up and recreates it in Down does not restore the data that was in it. Teams that treat Down as a safety net should test it on a disposable database before relying on it in an incident.

The broader limitation is that FluentMigrator has no knowledge of your application's model. It will happily create a schema that your ORM cannot map, and it will not tell you when a migration conflicts with an entity definition. If your project already uses Entity Framework Core, EF Core migrations and FluentMigrator both want to own the version table and the schema, and running both against one database is a way to produce exactly the drift the framework exists to prevent.

There is also a category of change the migration model handles poorly: long-running data backfills, index rebuilds on large tables, and anything that needs to be paused or resumed. A migration is a unit that either ran or did not. Operations that take hours inside a deployment window need a different mechanism, and the framework does not provide one.

Finally, single-database projects with a small team may not need it at all. If one developer owns the schema and there is no test database to keep in step, a versioned folder of SQL scripts is fewer moving parts, and the framework's value comes from coordination across environments.

## FluentMigrator compared with EF Core migrations and DbUp

The two comparisons people search for most are against EF Core migrations and against DbUp, and the difference is architectural rather than cosmetic.

EF Core migrations are generated from the entity model. You change a class, run the tooling, and it produces a migration that reflects the diff between the model and the last snapshot. FluentMigrator starts from the other direction: you write the schema change by hand, and there is no model to diff against. That means FluentMigrator can manage databases that no entity model describes, including schemas shared with other applications, and it does not force the migration tool and the ORM to agree on a snapshot. The cost is that you write every migration yourself and nothing checks it against the application's expectations.

DbUp is closer in spirit but makes a different trade. It runs ordered SQL scripts and records them, without a fluent C# API. If your team is comfortable in SQL and wants the migration history to be readable as SQL, DbUp's approach is more direct. FluentMigrator's fluent API and its per-database behaviour are the reason to choose it instead: the same migration class is intended to run against SQL Server, PostgreSQL and the rest, with the provider translating the operations. That translation layer is also where the abstraction leaks, since engine-specific syntax eventually has to be written as raw SQL.

The honest summary is that FluentMigrator fits teams that want schema changes as reviewed C# and do not want the migration tool coupled to an ORM. It fits less well when the ORM already owns the schema, or when SQL is the team's preferred language for schema work.

## Maintenance, licensing and the upgrade cost of a migration framework

The repository is not archived, and the last push was on 2026-09-01, which puts it inside the last six months. The release history shows v8.0.1 on 2026-01-20, v8.0.0 on 2026-01-13 and v7.2.0 on 2025-12-01. The project is being maintained, and the release notes describe a pattern of dropping old target frameworks as new .NET versions arrive: 7.0.0 removed net6.0 and net7.0 support, 6.0.0 removed a substantial amount of obsolete code, and 5.0.0 and 5.2.0 made smaller API changes. Upgrades are not free, but the notes suggest the project tries to keep user impact small and points to an upgrade guide for the 2.x to 3.0 transition.

The upgrade cost that matters for adopters is not the package version. It is the migration history. Once a schema is under FluentMigrator's version table, switching tools means reconciling that table with whatever the new tool records, and that reconciliation has to happen in every environment. Choosing the framework is closer to a multi-year commitment than a library choice.

The licence is Apache-2.0, which permits commercial use and modification and includes an explicit patent grant. That is a permissive licence, and it is compatible with proprietary applications. This is a description of the licence text, not legal advice; teams with specific obligations should read LICENSE.txt in the repository and consult their own counsel. The README also lists third-party ecosystem packages and states they are not endorsed, so anything outside the core packages is maintained on its own schedule.

## Conclusion

Adopt FluentMigrator when schema changes are written by .NET developers, reviewed in pull requests, and applied to more than one database (local, test, production) where a manually shared SQL script would drift. Skip it when your team already runs EF Core migrations against the same model, or when your database is a warehouse where DDL is governed by a separate change process; two migration authorities on one schema is how version tables get out of sync. Before the first production run, verify the runner command your deployment pipeline will actually invoke, confirm the version table name and schema your configuration produces, and test a Migrate Down on a disposable database so you know what rollback really does.

## FAQ

### How do you use FluentMigrator in a .NET project?

You write a class with the [Migration] attribute and a version number, implement Up and Down with the fluent API, and apply it with a runner such as the console migrator or MSBuild task shown in the repository samples. The runner records applied versions in a version table so each migration runs once per database.

### What is FluentMigrator?

It is a migration framework for .NET, described in its README as much like Ruby on Rails Migrations. Schema changes are written as C# classes that are checked into version control and applied to each database by a runner.

### What is the difference between FluentMigrator and EF Core migrations?

EF Core migrations are generated from the entity model, while FluentMigrator migrations are written by hand as schema changes with no model to diff against. That lets FluentMigrator manage schemas no entity model describes, but nothing checks a migration against the application's expectations.

## Sources

- [fluentmigrator/fluentmigrator on GitHub](https://github.com/fluentmigrator/fluentmigrator)
- [License: Apache-2.0](https://github.com/fluentmigrator/fluentmigrator/blob/main/LICENSE)
- [Project website](https://fluentmigrator.github.io)
- [README](https://github.com/fluentmigrator/fluentmigrator/blob/main/README.md)
- [Releases](https://github.com/fluentmigrator/fluentmigrator/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/fluentmigrator-fluentmigrator
