{"id":19383295,"url":"https://github.com/rebus-org/migr8","last_synced_at":"2025-10-06T11:24:49.314Z","repository":{"id":3784953,"uuid":"4862798","full_name":"rebus-org/migr8","owner":"rebus-org","description":":seedling: Short'n'sweet SQL Server/PostgreSQL/MySQL schema migration library","archived":false,"fork":false,"pushed_at":"2024-01-30T12:12:42.000Z","size":5771,"stargazers_count":40,"open_issues_count":0,"forks_count":6,"subscribers_count":9,"default_branch":"master","last_synced_at":"2024-05-01T11:48:08.145Z","etag":null,"topics":["c-sharp","database","migration-tool","migrations","sql","sql-server"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rebus-org.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2012-07-02T17:33:05.000Z","updated_at":"2024-04-18T16:50:01.000Z","dependencies_parsed_at":"2023-01-11T16:33:22.223Z","dependency_job_id":"fd2bba79-e7f9-4715-92b7-9952a2ef5c02","html_url":"https://github.com/rebus-org/migr8","commit_stats":null,"previous_names":[],"tags_count":36,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rebus-org%2Fmigr8","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rebus-org%2Fmigr8/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rebus-org%2Fmigr8/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rebus-org%2Fmigr8/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rebus-org","download_url":"https://codeload.github.com/rebus-org/migr8/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":223934070,"owners_count":17227646,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["c-sharp","database","migration-tool","migrations","sql","sql-server"],"created_at":"2024-11-10T09:25:26.322Z","updated_at":"2025-10-06T11:24:49.235Z","avatar_url":"https://github.com/rebus-org.png","language":"C#","readme":"# Migr8\r\n\r\nFirst you install the appropriate Migr8 package - if you're using SQL Server, you will probably\r\n\r\n\tInstall-Package Migr8 -ProjectName YourApp\r\n\r\nand if you're using PostgreSQL, you be all\r\n\r\n\tInstall-Package Migr8.Npgsql -ProjectName YourApp\r\n\r\nand then you will be good to go :)\r\n\r\n## Let's migrate\r\n\r\nExecute the migrations - either in a dedicated command line app, or - my favorite - whenever your app starts up,\r\njust before it connects to the database:\r\n\r\n```csharp\r\nvar connectionString = GetConnectionStringFromSomewhere();\r\n\r\nDatabase.Migrate(connectionString, Migrations.FromThisAssembly());\r\n```\r\n\r\nand then, elsewhere in the calling assembly, you define these bad boys (which happen to be valid T-SQL):\r\n\r\n```csharp\r\n[Migration(1, \"Create table for the Timeout Manager to use\")]\r\nclass CreateRebusTimeoutsTable : ISqlMigration\r\n{\r\n    public string Sql =\u003e @\"\r\n\t\tCREATE TABLE [dbo].[RebusTimeouts](\r\n\t\t\t[id] [int] IDENTITY(1,1) NOT NULL,\r\n\t\t\t[due_time] [datetimeoffset](3) NOT NULL,\r\n\t\t\t[headers] [nvarchar](MAX) NOT NULL,\r\n\t\t\t[body] [varbinary](MAX) NOT NULL,\r\n\t\t\tCONSTRAINT [PK_RebusTimeouts] PRIMARY KEY NONCLUSTERED \r\n\t\t\t(\r\n\t\t\t\t[id] ASC\r\n\t\t\t)\r\n\t\t)\r\n\t\"; \r\n}\r\n\r\n[Migration(2, \"Create a table for Rebus publishers to use\")]\r\nclass CreateRebusSubscriptionsTable : ISqlMigration\r\n{\r\n    public string Sql =\u003e @\"\r\n\t\tCREATE TABLE [dbo].[RebusSubscriptions] (\r\n\t\t\t[topic] [nvarchar](200) NOT NULL,\r\n\t\t\t[address] [nvarchar](200) NOT NULL,\r\n\t\t\tCONSTRAINT [PK_RebusSubscriptions] PRIMARY KEY CLUSTERED \r\n\t\t\t(\r\n\t\t\t\t[topic] ASC,\r\n\t\t\t\t[address] ASC\r\n\t\t\t)\r\n\t\t)\r\n\t\"; \r\n}\r\n```\r\n\r\nIn the example above, I've created two migrations which will be executed in they order indicated by their\r\n _sequence number_.\r\n\r\n## Branch specifications\r\n\r\nSince you will most likely not be the only one developing things in your application, you might have adopted\r\na _git flow_-inspired branching model, where each developer will create a branch to work in.\r\n\r\nFor example, two developers working in the `feature/first-cool-thing` and `feature/next-cool-thing` branches\r\nmight need to create the next migration. In the old days, one of them would be the unfortunate one to last\r\nintegrate _migration 3_ back into master, it would be necessary to change the migration to be number 4 and\r\nprobably execute the other developer's migration manually.\r\n\r\nLuckily, they chose to use Migr8 to evolve their database, so they just go ahead and create\r\n\r\n```csharp\r\n[Migration(3, \"Table for the first cool thing\", branchSpecification: \"first-cool-thing\")]\r\nclass CreateTableForTheFirstCoolThing : ISqlMigration\r\n{\r\n    public string Sql =\u003e @\"\r\n        CREATE TABLE [dbo].[firstCoolTable] ([id] int)\r\n    \"; \r\n}\r\n```\r\nand\r\n```csharp\r\n[Migration(3, \"Table for the next cool thing\", branchSpecification: \"next-cool-thing\")]\r\nclass CreateTableForTheNextCoolThing : ISqlMigration\r\n{\r\n    public string Sql =\u003e @\"\r\n        CREATE TABLE [dbo].[nextCoolTable] ([id] int)\r\n    \"; \r\n}\r\n```\r\nwhich will NOT BE A PROBLEM AT ALL, because they remembered to set the `branchSpecification` to the names\r\nof their branches.\r\n\r\nMigr8 will use the branch specifications to keep track of which migrations it has executed in the database,\r\nand it will then ensure that all migrations are applied eventually.\r\n\r\nJust remember that the sequence number positions a migration in a global sequence, which then effectively\r\nfunctions as a way to specify on which version of the already-existing schema each migration depends.\r\n\r\n## More information\r\n\r\nBy default, the table `[__Migr8]` is used to track extensive information on applied migrations - including\r\nthe full SQL that was executed + more.\r\n\r\nEach migration is executed in a SERIALIZABLE transaction - execution stops if one fails.\r\n\r\nIf you `go` in your SQL script, the preceding block will be executed - just like you're used to when working\r\nin SQL Server Management Studio.\r\n\r\nThe migrator competes perfectly for getting to apply the next migration, which guarantees no surprises even\r\nif you run the migrator at startup in your multi-instance Azure Website, or on a web farm.\r\n\r\n## What to do?\r\n\r\nFirst: Use Migr8 if you need to treat your database with some evolutionary friction-free schema and data\r\nmigrations.\r\n\r\nSecond: _lean back, chill....._\r\n\r\n## What else can you do?\r\n\r\nYou can also\r\n\r\n```csharp\r\nvar dir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, \"migrations\");\r\n\r\nDatabase.Migrate(\"db\", Migrations.FromFilesIn(dir));\r\n```\r\nin order to pick up migrations from files named on the form `\"\u003csequence-number\u003e-\u003cbranch-specification\u003e.sql\"`,\r\ne.g. organized like this:\r\n\r\n    /v01_00_00\r\n        0001-master.sql\r\n\r\n        /feature-a\r\n            0002-feature-a.sql\r\n            0003-feature-a.sql\r\n            0004-feature-a.sql\r\n        \r\n        /feature-b\r\n            0002-feature-b.sql\r\n            0003-feature-b.sql\r\n   \r\n    /v01_01_00\r\n        0005-master.sql     \r\n\r\nallowing you to keep track of a huge number of migrations, probably only needing to move a few of them around\r\nwhenever you integrate a feature branch with master. Comments added at the beginning of the `.sql` file will be\r\ntreated as the migration's description.\r\n\r\nAn SQL file-based migration could look like this:\r\n\r\n```sql\r\n-- Create some tables\r\n-- This initial comment will be included as the Description in the migration log\r\n\r\n-- This comment is NOT part of the block above and will simply be part of the logged SQL\r\nCREATE TABLE [Table1] ([Id] INT)\r\nGO\r\n-- Same thing with this comment\r\nCREATE TABLE [Table2] ([Id] INT)\r\n```\r\n\r\n## Is there more?\r\n\r\nOne last thing - if you prefer to log things using a logging library, e.g. like the excellent\r\n[Serilog](https://github.com/serilog/serilog), you can make Migr8 output its text to Serilog like this:\r\n\r\n```csharp\r\nvar connectionString = GetConnectionStringFromSomewhere();\r\nvar options = new Options(logAction: text =\u003e Log.Information(text));\r\n    \r\nDatabase.Migrate(connectionString, Migrations.FromAssemblyOf\u003cFirstMigration\u003e(), options);\r\n```\r\n\r\nwhich is probably what you want to do in all of your applications to be sure that Migr8 was properly invoked.\r\nMoreover, if you like, you can change the table that Migr8 uses to store its migration log like this:\r\n\r\n```csharp\r\nvar connectionString = GetConnectionStringFromSomewhere();\r\nvar options = new Options(migrationTableName: \"__MilliVanilli\");\r\n    \r\nDatabase.Migrate(connectionString, Migrations.FromAssemblyOf\u003cFirstMigration\u003e(), options);\r\n```\r\n\r\nso it doesn't collide with all your other tables named `[__Migr8]`.\r\n\r\n## Transactions, locking and such\r\n\r\nMigr8 gains exclusive access to the database whenever it wants to execute a migration by starting a\r\ntransaction with isolation level SERIALIZABLE, and then it tries to perform an INSERT into the\r\ntable that it uses to track migrations.\r\n\r\nThe inserted row has a migration ID on the form `\u003cnumber\u003e-\u003cbranch-specification\u003e`, which means\r\nthat being able to carry out the insert without any conflicts effectively works as taking a named\r\nlock.\r\n\r\nAfter that, the same transaction will be used to execute the migration. If the migration contains\r\nthe special `GO` statement (which is an SQL Server Management Studio construction), then each\r\nmigration will be executed in its own SQL command, but inside the same transaction.\r\n\r\nIf you DO NOT want to execute a migration inside a transaction, e.g. if you want to change\r\nthe database's recovery mode, you can have the migration executed on its own separate SQL connection \r\nwithout a trasaction by specifying the `no-transaction` flag.\r\n\r\nIf you're using migration classes, you can do it like this by using the `[Hint(...)]` attribute combined\r\nwith the predefined hint `Hints.NoTransaction`:\r\n\r\n```csharp\r\n[Migration(1, \"Prepare for big migration\")]\r\n[Hint(Hints.NoTransaction)]\r\npublic class SetRecoveryModeSimple : ISqlTransaction\r\n{\r\n\tpublic string Sql =\u003e \"alter database current set recovery simple\";\r\n}\r\n```\r\n\r\nIf you're using SQL files, you can pass hints to the execution engine by having the text `hints:` as part\r\nof the initial comment of the file, e.g. like this:\r\n\r\n```sql\r\n-- Prepare for big migration\r\n-- hints: no-transaction\r\n\r\nalter database current set recovery simple\r\n```","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frebus-org%2Fmigr8","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frebus-org%2Fmigr8","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frebus-org%2Fmigr8/lists"}