.NET · C#

FluentMigrator migrations, drawn as a database diagram

C# migration classes with a fluent API, numbered by the [Migration] attribute. SchemaDrawer runs FluentMigrator 8.0.1 on .NET 10 against a throw-away database of the engine you choose and returns an SVG of the schema it produces.

What to upload

Upload the C# migration classes, at any depth. Each class derives from Migration and carries a [Migration(version)] attribute. The files are compiled at run time against FluentMigrator and its PostgreSQL, MySQL and Oracle extension packages; no other NuGet package is available.

The sample below is the PetClinic schema written for FluentMigrator, one of the sets SchemaDrawer's own tests draw on every engine:

Migrations/
├── 20240101000001_CreateOwnersAndPets.cs
├── 20240101000002_CreateVets.cs
└── 20240101000003_CreateVisits.cs

Formats

C# source files.

How it runs

dotnet build of a project holding your files, then MigrateUp() through the FluentMigrator runner. The database is a fresh PostgreSQL, MySQL, MariaDB, SQL Server, Oracle or SQLite container in the version you ask for; nothing of yours is touched.

Databases you can draw FluentMigrator on

PostgreSQL 10, 11, 12, 13, 14, 15, 16, 17, 18 MySQL 8.0, 8.4, 9 MariaDB 10.6, 11.4, 11.8, 12 SQL Server 2017, 2019, 2022, 2025 Oracle 21, 23 SQLite

Not offered for FluentMigrator: SQLite. The tool ships no driver for it, so nothing could run.

At a glance

Runs
FluentMigrator 8.0.1 on .NET 10
API value
migrationType=FLUENT_MIGRATOR
Engines
5 of 6: PostgreSQL, MySQL, MariaDB, SQL Server, Oracle
Output
SVG diagram with tables, columns and types, primary and foreign keys
Price
Free today; enterprise plans are coming
Example

The PetClinic schema in FluentMigrator

Owners, pets, types, vets, specialties and visits: the same seven tables every sample set on this site creates. These are the exact files the tests upload.

using FluentMigrator;

namespace Migrations;

[Migration(20240101000001)]
public class CreateOwnersAndPets : Migration
{
    public override void Up()
    {
        Create.Table("owners")
            .WithColumn("id").AsInt32().NotNullable().PrimaryKey("pk_owners")
            .WithColumn("first_name").AsString(50).NotNullable()
            .WithColumn("last_name").AsString(50).NotNullable()
            .WithColumn("address").AsString(255).Nullable()
            .WithColumn("city").AsString(80).Nullable()
            .WithColumn("telephone").AsString(20).Nullable();

        Create.Table("types")
            .WithColumn("id").AsInt32().NotNullable().PrimaryKey("pk_types")
            .WithColumn("name").AsString(80).NotNullable();

        Create.Table("pets")
            .WithColumn("id").AsInt32().NotNullable().PrimaryKey("pk_pets")
            .WithColumn("name").AsString(50).NotNullable()
            .WithColumn("birth_date").AsDate().Nullable()
            .WithColumn("type_id").AsInt32().NotNullable().ForeignKey("fk_pets_types", "types", "id")
            .WithColumn("owner_id").AsInt32().NotNullable().ForeignKey("fk_pets_owners", "owners", "id");
    }

    public override void Down()
    {
        Delete.Table("pets");
        Delete.Table("types");
        Delete.Table("owners");
    }
}
using FluentMigrator;

namespace Migrations;

[Migration(20240101000002)]
public class CreateVets : Migration
{
    public override void Up()
    {
        Create.Table("vets")
            .WithColumn("id").AsInt32().NotNullable().PrimaryKey("pk_vets")
            .WithColumn("first_name").AsString(50).NotNullable()
            .WithColumn("last_name").AsString(50).NotNullable();

        Create.Table("specialties")
            .WithColumn("id").AsInt32().NotNullable().PrimaryKey("pk_specialties")
            .WithColumn("name").AsString(80).NotNullable();

        // The composite key and both foreign keys are declared inside the table rather than added
        // afterwards. SQLite cannot add either to a table that already exists, and FluentMigrator
        // does not refuse in advance - it writes the ALTER TABLE and hands back SQLite's complaint.
        // Named inline, the two columns make one composite key, and every engine takes it.
        Create.Table("vet_specialties")
            .WithColumn("vet_id").AsInt32().NotNullable().PrimaryKey("pk_vet_specialties")
                .ForeignKey("fk_vet_specialties_vets", "vets", "id")
            .WithColumn("specialty_id").AsInt32().NotNullable().PrimaryKey("pk_vet_specialties")
                .ForeignKey("fk_vet_specialties_specialties", "specialties", "id");
    }

    public override void Down()
    {
        Delete.Table("vet_specialties");
        Delete.Table("specialties");
        Delete.Table("vets");
    }
}
using FluentMigrator;

namespace Migrations;

[Migration(20240101000003)]
public class CreateVisits : Migration
{
    public override void Up()
    {
        Create.Table("visits")
            .WithColumn("id").AsInt32().NotNullable().PrimaryKey("pk_visits")
            .WithColumn("pet_id").AsInt32().NotNullable().ForeignKey("fk_visits_pets", "pets", "id")
            .WithColumn("visit_date").AsDate().Nullable()
            .WithColumn("description").AsString(255).Nullable();
    }

    public override void Down()
    {
        Delete.Table("visits");
    }
}
diagram.svg
ER diagram of the PetClinic schema drawn by SchemaDrawer: owners, pets, types, vets, specialties, vet_specialties and visits with their columns, primary keys and foreign keys

Every variant of the sample produces these seven tables. This diagram was drawn from the Flyway variant on PostgreSQL 18; on MySQL the types read INT and VARCHAR, on Oracle the names are upper case.

Run it

Draw your FluentMigrator migrations

One multipart request queues the drawing; poll the job until it succeeds and download the SVG. Or let the GitHub Action do it and open a pull request with the diagram.

With curl

curl -X POST https://schemadrawer.com/api/v1/drawing \
  -H "Request-Id: $(uuidgen)" \
  -F "userId=5f0c1d2e-3a4b-4c5d-8e6f-7a8b9c0d1e2f" \
  -F "migrationType=FLUENT_MIGRATOR" \
  -F "databaseType=POSTGRESQL" \
  -F "version=18" \
  -F "files=@Migrations/20240101000001_CreateOwnersAndPets.cs" \
  -F "files=@Migrations/20240101000002_CreateVets.cs" \
  -F "files=@Migrations/20240101000003_CreateVisits.cs"
# {"jobId":"0b6e2f4c-8d1a-4c3e-9f7a-2a5b6c7d8e9f"}

Then poll GET https://schemadrawer.com/api/v1/drawing/{jobId} until status is SUCCESS and fetch diagramUrl. Details in the getting started guide and the API reference.

With the GitHub Action

- uses: schemadrawercom/action@v1
  with:
    sql-directory: Migrations
    output-path: docs/schema-diagram.svg
    migration-type: FLUENT_MIGRATOR
    database-type: POSTGRESQL
    database-version: '18'
    github-token: ${{ secrets.GITHUB_TOKEN }}

The action uploads the directory, waits for the diagram and opens a pull request with the SVG. See the action reference.

Good to know

  • A compiler error comes back as the job's error message, with the compiler's own words.
  • MariaDB is migrated with the MySQL dialect, because FluentMigrator has no MariaDB one.
  • The VersionInfo table is left out of the diagram.
  • A drawing may take up to 120 seconds; a job that waits in the queue longer than 10 minutes fails rather than draws. Uploads of up to 100 MB and 2000 files are accepted.
From the blog

Reading about FluentMigrator and migrations

Draw your FluentMigrator schema now

Upload the migration directory, get an SVG back. Free while we build it.