Database Migrations
Managing database schema changes with Entity Framework Core — running, creating, reverting, and auto-applying migrations.
Overview
ZapTicket uses Entity Framework Core (EF Core) for database migrations. Migrations are C# files that describe schema changes — they're committed to source control and applied to the database either at startup or manually via CLI.
Running Migrations
Option 1: Auto-Run on Startup
Set the RUN_MIGRATIONS_ON_STARTUP environment variable to true. The backend will apply all pending migrations when it starts:
RUN_MIGRATIONS_ON_STARTUP=trueThis is the recommended approach for development and simple deployments. The application checks for pending migrations and applies them before accepting traffic.
Option 2: Manual CLI
For production deployments where you want more control, run migrations manually before deploying the new code:
cd backend
# Apply all pending migrations
dotnet ef database update
# Apply to a specific connection string
dotnet ef database update --connection "Host=prod-db.example.com;Database=zapticket;Username=admin;Password=..."
# See what would be applied (dry run)
dotnet ef migrations listdotnet ef migrations script (see below). This prevents surprises from destructive schema changes.Creating New Migrations
When you modify an entity class or DbContext configuration, create a migration to capture the schema diff:
cd backend
# Create a new migration
dotnet ef migrations add AddTicketPriority
# This creates:
# Migrations/
# 20240115120000_AddTicketPriority.cs (up/down logic)
# 20240115120000_AddTicketPriority.Designer.cs (snapshot)Best practices for naming migrations:
- Use descriptive PascalCase names:
AddTicketPriority,CreateMessagesTable - Prefix with the action:
Add,Create,Remove,Rename,Update - Keep names short but clear about what changed
Generating SQL Scripts
For auditing or manual application in production, generate the raw SQL:
# Generate SQL for all pending migrations
dotnet ef migrations script --idempotent -o migrations.sql
# Generate SQL between two specific migrations
dotnet ef migrations script PreviousMigration CurrentMigration -o changes.sql
# Generate from the beginning (full schema)
dotnet ef migrations script 0 -o full-schema.sql--idempotent flag wraps each migration in a conditional check, making it safe to run multiple times. Use this for production scripts.Reverting Migrations
To undo the most recent migration (before it's been pushed/deployed):
# Revert the database to the previous migration
dotnet ef database update PreviousMigrationName
# Remove the migration file (only if not yet applied to production)
dotnet ef migrations removeTo revert to a specific earlier migration:
# List migrations to find the target
dotnet ef migrations list
# Revert to a specific migration (undoes everything after it)
dotnet ef database update 20240110090000_CreateTenantsTableMigration File Structure
public partial class AddTicketPriority : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "Priority",
table: "Tickets",
type: "text",
nullable: false,
defaultValue: "medium");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "Priority",
table: "Tickets");
}
}The Up method applies the change. The Down method reverts it. Always implement both for reversibility.
Deployment Workflow
1. Develop locally with RUN_MIGRATIONS_ON_STARTUP=true
2. Create migration: dotnet ef migrations add <Name>
3. Test locally (auto-applies on restart)
4. Review generated SQL: dotnet ef migrations script --idempotent
5. Commit migration files to source control
6. Deploy:
- Option A: Set RUN_MIGRATIONS_ON_STARTUP=true (simple)
- Option B: Run dotnet ef database update manually, then deploy code