Nathaniel Nunes

Altering Custom Table Columns in Umbraco Migrations

·Nathaniel Nunes

The other day, a colleague came to me with a question:

How do I alter a column in our custom Umbraco table so it uses NVARCHAR(MAX) instead of a fixed length? Right now it’s defined as NVARCHAR(500), but we need more room.

It’s one of those practical problems that does not come up often, but when it does, you want a clear answer ready to go. So I thought I would capture the two approaches we tried for future reference.

The challenge

We had a custom table BlogComments with a column Message defined as NVARCHAR(500). That was fine at first, but later we needed to store much larger values.

So we explored two different solutions.

Approach 1: Using Raw SQL Directly Inside a Migration

The first approach was to go straight to SQL.

Using an Umbraco scope around the ALTER TABLE statements ensured the changes ran as part of the migration process and applied cleanly to SQL Server.

public class AlterCommentsTable : MigrationBase
{
    private readonly IScopeProvider _scopeProvider;
    public AlterCommentsTable(IMigrationContext context, IScopeProvider scopeProvider) : base(context)
    {
        _scopeProvider = scopeProvider;
    }

    protected override void Migrate()
    {
        Logger.LogDebug("Running migration {MigrationStep}", "AlterCommentsTable");

        // Check if table exists before altering
        if (TableExists("BlogComments"))
        {
            // Create Umbraco scope for DB operations
            using (var scope = _scopeProvider.CreateScope())
            {
                // Run raw SQL to alter column to NVARCHAR(MAX)
                scope.Database.Execute(@"ALTER TABLE BlogComments ALTER COLUMN Message NVARCHAR(MAX)");

                // Mark scope as complete
                scope.Complete();
            }
        }
        else
        {
            Logger.LogDebug("The database table {DbTable} doesn't exist, skipping", "BlogComments");
        }
    }
}

Approach 2: Fluent Migrations, Custom SQL Style

The second approach was to stay closer to the Migration API but use AsCustom(...) to declare the SQL type directly.

public class AlterCommentsTable : MigrationBase
{
    public AlterCommentsTable(IMigrationContext context) : base(context) { }

    protected override void Migrate()
    {
        var tableName = "BlogComments";
        var columnName = "Message";

        Logger.LogDebug("Running migration {MigrationStep}", "AlterCommentsTable");

        // Check if the column and table exist before altering
        if (ColumnExists(tableName, columnName))
        {
            // Use fluent API with AsCustom to set NVARCHAR(MAX)
            Alter.Table(tableName)
                .AlterColumn(columnName)
                .AsCustom("nvarchar(MAX)")
                .Do();
        }
        else
        {
            Logger.LogDebug("The database table {DbTable} or {ColumnName} doesn't exist, skipping", tableName, columnName);
        }
    }
}

This keeps the migration fluent style but gives you the flexibility to specify types that are not directly supported by the built‑in helpers.


Final thoughts

We explored two ways to handle NVARCHAR(MAX) in Umbraco migrations. Hopefully this guide saves you time when you encounter a similar issue.

If you have tackled this problem in another way or have tips to improve these approaches, I would love to hear your perspective.

Cover photo by Sergi Ferrete