A web application for assessing, planning, and executing SQL Server database migrations to Azure SQL services.
- Assessment Engine — Analyzes source SQL Server databases for schema, data profile, and workload metrics
- Compatibility Matrix — Evaluates compatibility across Azure SQL Database, Hyperscale, Managed Instance, and SQL Server on Azure VM
- Tier Recommendation — Recommends the optimal Azure SQL service tier based on workload and compatibility
- Azure Pricing Integration — Real-time cost estimates from the Azure Retail Prices API across all regions
- Migration Scripts — Auto-generates pre/post migration scripts (drop/restore FKs, indexes, triggers, constraints) with custom script support
- Bulk Data Migration — SqlBulkCopy-based data transfer with FK dependency ordering and progress tracking
- Continuous Sync — Change Tracking-based incremental replication with manual cutover for minimal downtime
- Post-Migration Validation — Row count and checksum verification between source and target
- Real-Time Progress — SignalR-based live migration progress updates
┌─────────────────┐ ┌─────────────────────────────────────────────┐
│ Scaffold.Web │ │ Scaffold.Api │
│ React / Vite │──────▶│ ASP.NET Core 8 API │
│ Fluent UI v9 │ HTTP │ │
└─────────────────┘ + WS │ ┌───────────────────┐ ┌─────────────────┐ │
│ │Scaffold.Assessment│ │Scaffold.Migration│ │
│ │ Assessment engines│ │ Migration engines│ │
│ └────────┬──────────┘ └────────┬────────┘ │
│ │ │ │
│ ┌────────▼──────────────────────▼────────┐ │
│ │ Scaffold.Infrastructure │ │
│ │ EF Core · Repositories · Azure SDK │ │
│ └────────────────┬───────────────────────┘ │
└───────────────────┼─────────────────────────┘
│
┌─────────▼─────────┐
│ SQL Server │
│ (local / Azure) │
└───────────────────┘
Projects:
Scaffold.Core— Domain models, interfaces, enums. Zero dependencies.Scaffold.Assessment— Assessment engines per source platform (SQL Server assessor, compatibility checker, tier recommender, pricing service)Scaffold.Migration— Migration engines (schema deployer via DACPAC, bulk data copier, change tracking sync, script executor, validation)Scaffold.Infrastructure— EF Core data access, repositories, Azure SDK integrationsScaffold.Api— ASP.NET Core 8 Web API with SignalR hubsScaffold.Web— React 19 + Vite + Fluent UI v9 frontend
Source platform support is extensible via IAssessmentEngine and IMigrationEngine interfaces.
- .NET 8 SDK
- Node.js 20+
- Docker (for SQL Server and containerized deployment)
The fastest way to run Scaffold:
docker compose up --buildThis starts:
- SQL Server 2025 on port 1433
- API on port 8080
- Web UI on port 3000
Open http://localhost:3000 in your browser.
docker run -e "ACCEPT_EULA=Y" -e "MSSQL_SA_PASSWORD=YourStrong!Passw0rd" \
-p 1433:1433 --name sqlserver \
-d mcr.microsoft.com/mssql/server:2025-latestUpdate the connection string in src/Scaffold.Api/appsettings.Development.json if you use a different password.
cd src/Scaffold.Api
dotnet runThe API starts on http://localhost:5062 with authentication disabled for local development. The database is created automatically on first run via EF Core migrations.
cd src/Scaffold.Web
npm install
npm run devThe frontend starts on http://localhost:5173 and proxies API requests to the backend automatically.
dotnet test # All 211+ backend tests
cd src/Scaffold.Web && npx tsc --noEmit # Frontend type checkNote: Backend tests use an in-memory database — no SQL Server instance is required to run tests.
- Create a Project — Name your migration project
- Assess — Connect to a source SQL Server and run a compatibility assessment
- Review — View compatibility scores per Azure service, tier recommendations, and pricing estimates
- Plan — Select objects to migrate, configure target database, choose pre/post migration scripts
- Execute — Run the migration with real-time progress tracking and post-migration validation
- Azure CLI — logged in (
az login) - Azure Developer CLI (azd) — logged in (
azd auth login) - An Azure subscription with permissions to create resources (Contributor role or higher)
- Permissions to create Entra ID App Registrations (or an existing one to provide)
azd upYou'll be prompted to name your environment (e.g., dev, staging, prod). This name prefixes all Azure resources.
? Enter a new environment name: dev
Select the subscription and Azure region for deployment. Choose a region close to your users and source databases.
? Select an Azure Subscription to use: My Subscription (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)
? Select an Azure location to use: East US 2
The deployment will ask if you have an existing Entra ID App Registration:
Option A — Create a new one (recommended for first-time setup):
Do you have an existing Azure AD App Registration? (y/N): N
Creating new App Registration: scaffold-dev...
✓ App Registration created: <CLIENT_ID>
✓ Service Principal created
✓ SPA platform configured
✓ Microsoft Graph User.Read permission added
⚠ IMPORTANT: After deployment completes, an admin must grant API permissions:
az ad app permission admin-consent --id <CLIENT_ID>
Option B — Use an existing one:
Do you have an existing Azure AD App Registration? (y/N): y
Enter the Application (Client) ID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
Enter the Tenant ID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
Bicep deploys all infrastructure (~5-10 minutes):
- Azure SQL Database (Basic tier)
- Azure Container App (API)
- Azure Static Web App (frontend)
- Azure Container Registry (container images)
- Azure Key Vault (secrets)
- Azure Storage Account (migration artifacts)
The CLI builds the API Docker container and frontend, then deploys both (~3-5 minutes).
The deployment automatically updates the App Registration with the correct redirect URIs. A summary is displayed:
═══════════════════════════════════════════
Scaffold Deployment Summary
═══════════════════════════════════════════
Frontend URL: https://your-app.azurestaticapps.net
API URL: https://your-api.azurecontainerapps.io
Client ID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
═══════════════════════════════════════════
If a new App Registration was created, run:
az ad app permission admin-consent --id <CLIENT_ID>This grants the app permission to read user profiles. Without this step, users cannot sign in.
To update code without re-provisioning infrastructure:
azd deployTo update infrastructure and code:
azd upTo remove all Azure resources:
azd down --purge| Resource | Purpose |
|---|---|
| Azure SQL Database | Scaffold metadata store |
| Azure Container App | API backend (.NET 8) |
| Azure Static Web App | Frontend (React) |
| Azure Container Registry | API container image hosting |
| Azure Key Vault | Secret storage for database credentials |
| Azure Storage Account | Migration artifacts |
| Entra ID App Registration | User authentication (created or provided) |
| Variable | Description | Default |
|---|---|---|
ConnectionStrings__DefaultConnection |
Scaffold metadata database | Server=localhost;Database=ScaffoldDb;... |
AzureAd__TenantId |
Entra ID tenant | Set by deployment |
AzureAd__ClientId |
App Registration client ID | Set by deployment |
DisableAuth |
Disable authentication (dev only) | false |
⚠️ Warning: Never setDisableAuth=truein production.
See CONTRIBUTING.md for development guidelines.
The API waits for SQL Server to be healthy before starting. If the health check fails, verify the SA password matches between the db and api services in docker-compose.yml.
This is a harmless ASP.NET Core warning from the test host. It does not indicate a test failure — check the actual test results.
Ensure the API is running on port 5062 before starting the frontend. Vite proxies /api requests to http://localhost:5062.
The API auto-applies EF Core migrations on startup. If you see migration errors, ensure your SQL Server is running and the connection string in appsettings.Development.json is correct. You can also apply migrations manually:
dotnet ef database update --project src/Scaffold.Infrastructure --startup-project src/Scaffold.ApiVerify the API is reachable and the browser console doesn't show WebSocket connection errors. In Docker, ensure the nginx config includes WebSocket upgrade headers for the /hubs/ path.
You need Azure AD admin permissions (Global Administrator or Privileged Role Administrator) to grant consent. Contact your Azure AD admin or have them run the command.
See LICENSE for details.