DBEvolve is a lightweight, deterministic database migration library for .NET that automates database creation, schema evolution, and version tracking using versioned SQL scripts. DBEvolve can: - Create a database if it does not exist - Execute SQL migration scripts in a controlled order - Track the current database version - Apply only the required scripts to upgrade an existing database - This library is for use with SqlServer Each migration script contains its version in the filename, allowing DBEvolve to determine exactly which scripts need to run based on the current database state. This makes upgrades predictable, repeatable, and safe across environments. Key features: - Automatic database creation - Version-based migration execution - Persistent schema version tracking - Idempotent upgrades (only new scripts are applied) - Validates that applied scripts haven't been modified using SHA-256 hashes - Simple, script-first migration model - Designed for CI/CD and automated deployments DBEvolve is ideal for teams that prefer explicit SQL scripts, clear versioning, and full control over how database changes are applied—without heavyweight configuration or ORM coupling.
$ dotnet add package SByteStream.DBEvolveLib.SqlServerDBEvolve is a lightweight, deterministic database migration library for .NET that automates database creation, schema evolution, and version tracking using versioned SQL scripts.
Automatic database creation - Creates the database if it doesn't exist
Version-based migration execution - Executes SQL scripts in a controlled, versioned order
Persistent schema version tracking - Tracks applied migrations in a version history table. The name of the version history table can be changed.
Idempotent upgrades - Only new scripts are applied; previously run scripts are skipped
Script integrity validation - Validates that applied scripts haven't been modified using SHA-256 hashes
Simple, script-first migration model - Full control over database changes using explicit SQL scripts
Designed for CI/CD - Perfect for automated deployments
Install the NuGet package:
dotnet add package SByteStream.DBEvolve.SqlServer
using Microsoft.Extensions.Logging; using SByteStream.DBEvolve;
// Create a logger (using any ILogger implementation)
ILogger logger = LoggerFactory.Create(builder => builder.AddConsole())
.CreateLogger("DBEvolve");
// Define your connection string
string connectionString = "Data Source=localhost;Initial Catalog=MyDatabase;Integrated Security=true;";
// Define the directory containing your SQL scripts
string scriptsDirectory = @"C:\MyProject\DbScripts";
// Create and run the evolver
var evolver = new SqlServerDBEvolver();
evolver.Evolve(logger, connectionString, scriptsDirectory);
DBEvolve uses a strict naming convention for SQL script files to determine the execution order and version:
V<MajorVersion>_<MinorVersion>__<Description>.sql
_)__) separates the version from the descriptioninitial_schema, add_users_table).sqlV01_00__initial_schema.sql -> Version 100 V01_01__add_users_table.sql -> Version 101 V01_02__create_indexes.sql -> Version 102 V02_00__add_orders_module.sql -> Version 200 V02_01__orders_stored_procs.sql -> Version 201
The numeric version is calculated as: (MajorVersion × 100) + MinorVersion
V01_00 = 1 × 100 + 0 = 100V01_01 = 1 × 100 + 1 = 101V02_00 = 2 × 100 + 0 = 200DBEvolve automatically creates and manages a version history table to track applied migrations.
__Version_History__
CREATE TABLE [Version_History]
(
VersionNumber INT NOT NULL PRIMARY KEY,
Filename NVARCHAR(512) NOT NULL,
FileHash VARBINARY(32) NOT NULL,
EntryDate DATETIME CONSTRAINT [DF____Version_History____EntryDate] DEFAULT (GETUTCDATE())
)
You can specify a custom version history table name:
var evolver = new SqlServerDBEvolver();
evolver.Evolve(logger, connectionString, scriptsDirectory, versionTableName: "MyCustomVersionTable");
Given these scripts in your directory: V01_00__initial_schema.sql V01_01__add_users.sql V01_02__add_orders.sql
First Run (Empty Database):
Second Run (Add New Script): V01_00__initial_schema.sql V01_01__add_users.sql V01_02__add_orders.sql V01_03__add_indexes.sql <- New script
You can upgrade to a specific version instead of the latest:
var evolver = new SqlServerDBEvolver(); // Upgrade only up to version 101
evolver.Evolve(logger, connectionString, scriptsDirectory, maxVersion: 101);
DBEvolve protects against accidental script modifications by:
⚠️ Never modify a script that has already been applied to any environment. Always create a new script with a higher version number for schema changes.
using Microsoft.Extensions.Logging; using SByteStream.DBEvolve;
var logger = LoggerFactory.Create(builder => builder.AddConsole())
.CreateLogger("DBEvolve");
var evolver = new SqlServerDBEvolver();
evolver.Evolve(logger: logger,
connectionString: "Data Source=localhost;Initial Catalog=MyDb;Integrated Security=true;",
scriptsDirectory: @".\DbScripts" );
var evolver = new SqlServerDBEvolver();
evolver.Evolve( logger: logger,
connectionString: connectionString,
scriptsDirectory: scriptsDirectory,
versionTableName: "MyApp_VersionHistory" );
var evolver = new SqlServerDBEvolver();
// Upgrade only to version 105
evolver.Evolve( logger: logger,
connectionString: connectionString,
scriptsDirectory: scriptsDirectory,
maxVersion: 105 );
var evolver = new SqlServerDBEvolver();
// Upgrade only to version 105
evolver.Evolve( logger: logger,
connectionString: connectionString,
scriptsDirectory: scriptsDirectory,
commandTimeoutSec: 60 );
using Microsoft.Extensions.Logging; using SByteStream.DBEvolve;
class Program
{
static void Main()
{
var loggerFactory = LoggerFactory.Create(builder =>
{
builder.AddConsole();
builder.SetMinimumLevel(LogLevel.Information);
});
var logger = loggerFactory.CreateLogger<Program>();
try
{
var evolver = new SqlServerDBEvolver();
evolver.Evolve(
logger: logger,
connectionString: "Data Source=localhost;Initial Catalog=MyAppDb;Integrated Security=true;",
scriptsDirectory: @"C:\MyProject\DbScripts"
);
logger.LogInformation("Database migration completed successfully!");
}
catch (DBEvolveException ex)
{
logger.LogError(ex, "Database migration failed: {Message}", ex.Message);
Environment.Exit(1);
}
}
}
All SQL statements of a script block are executed within a transaction. In case a statement generates an error, the transaction is rolled back and no entry is made for the script in the version table.
For SQL Server, use GO to separate batches in your scripts:
CREATE TABLE Users
(
Id INT PRIMARY KEY,
Name NVARCHAR(100)
);
GO
CREATE INDEX IX_Users_Name ON Users(Name);
GO
Keep scripts focused on a single logical change:
V01_05__add_users_table.sqlV01_06__add_orders_table.sqlV01_05__add_all_tables.sql (too broad)Make script descriptions meaningful:
V02_03__add_email_column_to_users.sqlV02_03__update.sqlOnce a script has been applied to any environment:
Copyright (C) 2026, Siddharth R Barman
Data migration icons created by Ida Desi Mariana - Flaticon
This project is source-available under the SByteStream No-Modification License.
For issues, questions, or contributions, please visit the project repository.
You can also contact me at sbytestream@outlook.com.