Deploying database schema changes in production environments can be risky without the right strategy. Entity Framework Core (EF Core) provides several ways to apply migrations, but not all are production-safe. At Assemblysoft, we specialise in .NET modernisation and help businesses implement reliable deployment pipelines for EF Core using proven practices.

In this article, we'll explore the various strategies for applying migrations to production databases, when to use each, and how Assemblysoft can support your team in adopting these best practices.


Why Migrations Matter

EF Core migrations allow developers to evolve their database schema over time in a controlled and repeatable manner. However, in production environments, this needs to be handled carefully to avoid:

  • Data loss
  • Downtime
  • Schema inconsistencies across environments

That’s where the right deployment approach becomes critical.


1. SQL Scripts – The Gold Standard

SQL script generation is the recommended method for applying migrations in production:

Benefits:

  • Reviewable: Scripts can be manually reviewed and approved before execution.
  • Auditable: Supports change tracking and versioning.
  • Safe: Reduces the risk of runtime surprises.
  • Customisable: Tailor queries for environment-specific considerations.
  • Automation ready: Integrate with CI/CD tools like GitHub Actions or Azure DevOps.

Example:

dotnet ef migrations script -o migrate.sql

You can also generate idempotent scripts for multi-tenant or distributed environments:

dotnet ef migrations script --idempotent -o migrate-safe.sql
Learn how Assemblysoft helps automate SQL-based deployments

2. Migration Bundles – Modern & Flexible

EF Core 6+ introduced migration bundles, which compile your migrations into a standalone executable. Perfect for:

  • Deployment teams without the .NET SDK installed
  • Environments with limited access
  • CI/CD pipeline integration

Benefits:

  • Self-contained: No EF tooling or SDK required
  • Environment-independent: Works across dev, test, and production
  • Scriptless: Ideal for infrastructure teams who prefer binary tools

Example:

dotnet ef migrations bundle --self-contained --target-runtime win-x64
.\efbundle.exe --connection "YourConnectionString"
🔧 Assemblysoft can help integrate this into your CI/CD process using GitHub Actions and deployment stages.

3. Command-line Tools – Good for Dev, Not Prod

Tools like Update-Database or dotnet ef database update work well during development but are not suited for production:

Risks:

  • Immediate schema changes with no review
  • Requires project source code and the SDK on the production server
  • Limited rollback capability

We recommend reserving these tools for local and QA environments.


4. Runtime Migrations (MigrateAsync()) – Use Caution

Applying migrations programmatically at app startup using context.Database.MigrateAsync() can be tempting—but it’s rarely safe in production:

Why it’s risky:

  • Requires elevated DB permissions
  • No rollback safety
  • Potential concurrency issues in load-balanced environments
using (var scope = host.Services.CreateScope())
{
    var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();
    await db.Database.MigrateAsync();
}
🚫 Avoid using this in production pipelines.

5. Development Mode Checks – The Best of Both Worlds

During development, it’s beneficial to auto-apply migrations to streamline testing and schema evolution. However, this should be gated by a check to ensure the app only does this in safe environments.

if (env.IsDevelopment())
{
    using var scope = host.Services.CreateScope();
    var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();
    await db.Database.MigrateAsync();
}

This allows teams to enjoy seamless developer experience while maintaining strict controls in production. Combined with Git-based migration reviews, this pattern offers a healthy balance between agility and safety.

⚙️ Assemblysoft helps implement dev-safe patterns like this across Blazor and .NET solutions.

Designing Migrations That Are Safe to Ship

Whichever mechanism you choose, the content of the migration matters as much as the delivery method. Before any migration reaches a pipeline, we review the generated code itself, not just the model change that produced it:

  • Watch for destructive scaffolding: a property rename can be generated as a drop-and-recreate of the column, silently discarding data. Edit the migration to use a rename operation instead.
  • Expand, then contract: ship additive changes first (new columns, new tables), deploy the application, backfill data, and only remove the old schema in a later release. This keeps two application versions compatible with the database during rollout.
  • Mind long-running operations: adding an index to a large table or altering a heavily used column can hold locks for minutes. Schedule these deliberately rather than letting them run mid-deployment.
  • Rehearse on realistic data: a script that runs instantly against a developer database can behave very differently against production volumes. Test against a restored copy first.
  • Confirm your way back: verify the backup or point-in-time restore position before applying anything, because a reviewed script is still not a rollback plan.

These habits matter most on systems that have accumulated years of schema history, which is why they are a standard part of our legacy .NET migration work and the wider .NET development engagements we run for clients with business-critical databases.


Assemblysoft: Your .NET Migration Experts

At Assemblysoft, we help teams implement secure, scalable, and automated database migration workflows using:

  • CI/CD pipelines with GitHub Actions or Azure DevOps
  • SQL script generation with review gates
  • Self-contained bundles for repeatable execution
  • Environment-based rollout strategies
  • Dev-mode safety checks for faster iteration

Our UK-based team of experienced developers and architects work closely with you to ensure your .NET applications evolve safely—without disrupting business continuity.

📌 Explore our Fullstack Blazor Development or Custom Software Development Services to see how we can help modernise your stack.


Conclusion

EF Core migrations are a powerful way to manage evolving database schemas—but only if used correctly. By adopting SQL scripts or bundles, adding dev-mode checks, and avoiding runtime risks in production, your team can ensure seamless, zero-downtime updates.

When you're ready to take your .NET application lifecycle to the next level, Assemblysoft is here to help.

Getting migrations flowing safely through a pipeline is exactly the kind of delivery plumbing we set up for clients — see our Azure DevOps services, or talk to us about your .NET delivery process.