07/26/2026
by Marlon Ribunal
0 comments

Introducing azsql-migration-test: Test and Validate Azure SQL Database Migrations

Disclaimer: Built with Claude Code

Introducing azsql-migration-test, a small open-source CLI that validates your Azure SQL Database migrations against a local Azure SQL Database Developer container — the same engine as the cloud, running on your machine.

The problem: proving a migration works shouldn’t require the cloud

If you run Azure SQL Database, you want to know a schema migration will succeed before you apply it in production. But the honest way to be sure has always meant testing against a live Azure SQL Database — which means a subscription, cloud spend, and slow round-trips every time you tweak the migration.

So validation gets rushed, done once instead of continuously, or skipped until staging — and the surprises show up late, mid-release, when they’re most expensive.

What’s been missing is a way to validate a migration against the actual Azure SQL Database engine, locally, repeatably, and for free.

What it is

Azure SQL Developer is the Azure SQL Database engine packaged as a local container. It’s the real thing running on your laptop — what works there deploys seamlessly to Azure SQL Database. More info on SQL Database Developer can be found here. Youtube Demo provided by MSFT can be found here.

azsql-migration-test automates the validation loop against it:

  1. Pull and start the Developer container.
  2. Extract your source schema (with sqlpackage).
  3. Deploy it into the container — the real compatibility test: if the engine won’t accept the schema, the deploy fails and so does validation.
  4. Replay your queries against the deployed schema.
  5. Tear everything down.

No cloud account. No cloud cost. Zero-to-answer in a couple of minutes — and because it’s the same engine you deploy to, a clean pass means a clean deploy.

The three commands

validate — the full pass

Extract the source schema, deploy it into the container (the compatibility test), then replay your queries against it:

Zsh
azsql-migration-test validate \
--source "Server=;Database=;User Id=;Password=" \
--queries ./queries.sql

✓ Schema deployed to Azure SQL Database Developer (compatible)
✓ Query replay complete: 12 passed, 0 failed
Migration validation completed successfully

If the schema is rejected or a query fails, it exits non-zero — so it drops straight into a script or a CI job.

compare — a non-destructive deployment dry-run

Report exactly what deploying your schema would do — every operation sqlpackage would run against the Azure SQL Database engine — without applying anything:

Zsh
azsql-migration-test compare \
--source "Server=;Database=;User Id=;Password="

✓ Schema comparison complete

You get a report.md summary and the raw schema-diff.xml:

Schema
Changes: 4 (breaking: false)
DeployReport: schema-diff.xml

Against a fresh target this is the full create plan; against a database that already has a schema (e.g. from a prior validate --keep) it’s the incremental diff — creates, alters, and drops. It exits non-zero when the plan contains a breaking operation — a drop or a data-loss alert — so it makes a clean pre-merge gate.

It exits non-zero when the diff contains a breaking operation — a drop or a data-loss alert — so it makes a clean pre-merge gate.

replay — run a query set

Run a set of GO-separated batches against a database and get per-batch pass/fail and timing:

Zsh
azsql-migration-test replay --queries ./smoke.sql --database MyDb

✓ Query replay complete: 8 passed, 0 failed

A failing batch exits non-zero and the SQL error is captured in the report:

[FAIL] SELECT * FROM dbo.Orders_old; (168ms)
Msg 208, Level 16, State 1 — Invalid object name 'dbo.Orders_old'.

Where it fits: use cases

  • A pre-deploy gate on your laptop. Before you open the PR, confirm the migration will be accepted by the Azure SQL Database engine.
  • A CI/CD check. Every command exits non-zero on failure, so you can wire it into a pipeline that blocks a merge or a deploy on a migration that won’t apply.
  • Repeatable validation across a migration project. Instead of a one-time cloud assessment, re-run it on every change — locally, for free.
  • Vetting third-party or generated migration scripts. Point it at a schema you didn’t write and see whether the engine accepts it before it reaches production.
  • Fast iteration. Change the migration, re-validate in a couple of minutes, no cloud round-trip.

Honest about what it does

Good tooling tells you where it stops. The breaking-change flag is derived from the sqlpackage DeployReport (drops and data-loss alerts); the full XML report is always written, so you can inspect the deployment plan yourself. As with any pre-deploy check, keep your normal staged rollout — but you’ll catch the schema problems that otherwise surface at deploy time, right on your laptop.

Try it in two minutes

Download a binary from the latest release (https://github.com/MarlonRibunal/azsql-migration-test/releases) (each ships with checksums), or:

Zsh
go install github.com/MarlonRibunal/azsql-migration-test@latest

Point it at an Azure SQL Database Developer container image you have access to (and its registry credentials, if needed) via environment variables, then run validate. Full quickstart and flags are in the README (https://github.com/MarlonRibunal/azsql-migration-test#readme).

You’ll need Docker and sqlpackage on your PATH. (sqlcmd runs inside the container, so you don’t need it on the host.)

Contribute — it’s small on purpose

azsql-migration-test is a compact, dependency-free Go CLI. That’s deliberate: it’s easy to read, easy to build, and easy to contribute to. If you work with Azure SQL migrations, there’s low-hanging fruit here:

  • Richer DeployReport parsing and smarter breaking-change classification.
  • A first-class GitHub Action wrapper for the CI use case.
  • More output formats (JSON, SARIF) for pipeline integration.
  • Real-world schema fixtures and edge cases worth validating against.

Issues and PRs are welcome — see CONTRIBUTING (https://github.com/MarlonRibunal/azsql-migration-test/blob/main/CONTRIBUTING.md). If it saved you a bad deploy, a ⭐ on the repo helps others find it.

https://github.com/MarlonRibunal/azsql-migration-test


azsql-migration-test is an independent, community project. It is not affiliated with, endorsed by, or sponsored by Microsoft. “Azure” and “Azure SQL Database” are trademarks of Microsoft Corporation.

07/23/2026
by Marlon Ribunal
0 comments

Getting Started with Azure SQL Developer on Macbook

No, this is not the SQL Server Developer Edition. This is something new (as of the time of writing). Well, it’s like the Developer Edition that you’ve all been familiar with in all the SQL Server versions. This Developer edition is for the cloud-only, PaaS Azure SQL Database. And, yeah, we would like to thank Microsoft for this!

The idea behind Azure SQL Developer is for anyone to build, iterate, and test locally at no cost. This means NO Azure subscription to deal with and NO credit card required! Everything will work seamlessly when you deploy your application to an Azure SQL Database backend!

It’s exactly like the SQL Server Developer Edition that we all love. As of this writing, it’s in Private Preview. And I got the chance to get into the preview program. Find more information about it here. There’s a short intro on youtube here.

I’d like to build something on top of Azure SQL Developer. But for now, let’s set it up on my dev environment:

Laptop: Macbook Pro M5 Pro
Code Editor: Zed 1.11.3
Terminal: iTerm2
Container App: OrbStack (my preferred container app on mac)
Database: Local Azure SQL Developer container
AI Coding Agent: Claude Code Max 5x

By the way, same steps should apply to Windows.

Authenticate to the Preview Registry

Like I said, Azure SQL Developer is currently in Private Preview. I was given a user and password to authenticate to the registry to pull the latest image.

Zsh
docker login sqldbpreview-dpgaeqhmgphzd4bk.azurecr.io -u private-preview-reader

Input the password that was sent to you when you get admitted to the private preview. Hopefully, pulling the image would be much more convenient when this goes public.

You should get a Login Succeeded message.

Pull the Azure SQL Developer image and deploy container

Let’s pull the image and deploy the Azure SQL Developer container to OrbStack.

Zsh
docker run --platform linux/amd64 -e ACCEPT_EULA=Y -e MSSQL_SA_PASSWORD='YourStrongPassword' -p 1433:1433 --name azuresqldb --hostname azuresqldb -d sqldbpreview-dpgaeqhmgphzd4bk.azurecr.io/azure-sql/db-dev:latest

Normally, I would pull the image first then deploy. But you can also directly deploy and docker should be able to pull the image first (duh).

Test connection to our local Azure Database Developer

Let’s send a query to the database to make sure we can establish a connection to it.

Zsh
docker exec azuresqldb /opt/mssql-tools18/bin/sqlcmd -S localhost -U sa -P 'YourStrongPassword' -C -Q 'SELECT @@VERSION;'

And if you’ve followed the steps correctly, you should now be able to connect to the local version of Azure SQL Database.

As of this writing, as you can see in the screenshot below, the current version of Azure SQL Database Developer is 12.0.2000.8, July 12, 2026

Enjoy! I’ll build something on top of this. Come back for that later!

07/20/2026
by Marlon Ribunal
0 comments

Restore SQL Server Database to an OrbStack Container

In the previous post, we’ve built a SQL Server 2025 sandbox in an OrbStack container in a Macbook. If you are like me who switched from a Windows laptop to MacBook, you are probably missing your SQL Server. Sometimes it’s just nice to have a sandbox that is separate from your all other instances for testing and learning. This is exactly what we’re trying to do here.

Download the Backup

For this exercise we want to download the full backup of Wide World Importers. Go ahead and download it from the github repo which you can find it here. And of course, take note of where you saved the .bak file.

Copy the Backup File into the Container

First, let’s create our backup directory in our cotainer. From your favorite terminal, run the following:

ShellScript
docker exec -it sql2025 mkdir -p /var/opt/mssql/backup

Then copy over the file to the directory we just created above

ShellScript
docker cp /Users/marlonribunal/Downloads/WideWorldImporters-Full.bak sql2025:/var/opt/mssql/backup/

You terminal should now say that the backup file was successfully copied.

Use VS Code to Restore the Database

Since Microsoft will never ever port SSMS to the macOS, I think VS Code with the mssql extension is a pretty much decent tool for doing work in a SQL Server.

Check the in-memory data, database, and log files contained in the backup, so we know what logical files to map to their physical paths in the container:

SQL
RESTORE FILELISTONLY
FROM DISK = N'/var/opt/mssql/backup/WideWorldImporters-Full.bak';
GO

You should see all the contained in the backup file of the WideWorldImporters database. Take note of those for the next step.

Then restore the database. Please take note that if you don’t map the path of the files to where you want to store them, the restore proccess will assume that you are restoring the files into the same directory the backup files were stored in the source. Chances are you will then get an error because those original directory don’t exist in the target container.

SQL
RESTORE DATABASE [WideWorldImporters]
FROM DISK = '/var/opt/mssql/backup/WideWorldImporters-Full.bak'
WITH 
MOVE 'WWI_Primary' TO '/var/opt/mssql/data/WideWorldImporters.mdf',
MOVE 'WWI_UserData' TO '/var/opt/mssql/data/WideWorldImporters_UserData.ndf',
MOVE 'WWI_Log' TO '/var/opt/mssql/data/WideWorldImporters_Log.ldf',
MOVE 'WWI_InMemory_Data_1' TO '/var/opt/mssql/data/WideWorldImporters_InMemory_Data_1',
REPLACE;
GO

That took about 8 seconds to complete in my container:

That’s it! Enjoy querying!

Verified by MonsterInsights