These skills teach an AI coding agent to use the Azure SQL Database container the right way. The Azure SQL Database container is the Azure SQL Database engine, running locally. It is for the developer who wants a local database that behaves like Azure SQL Database in the Microsoft Azure cloud, with no Azure subscription, no shared instance, and no credit card required. The container runs the same engine that powers Azure SQL Database in the cloud: the T-SQL dialect, the system views, the connection protocol, the driver behavior, and the AI-native capabilities are the same as in the cloud. The connection string changes; the application does not.
You can prove the identity from any connection:
SELECT SERVERPROPERTY('EngineEdition'); -- 5
SELECT SERVERPROPERTY('Edition'); -- 'SQL Azure'EngineEdition 5 and Edition 'SQL Azure' are the cloud engine's fingerprint. The SQL Server image (mcr.microsoft.com/mssql/server) returns different values and is not the same product. If an agent was about to reach for that SQL Server image, it should stop and use this instead.
Status: Private Preview. Registry, image tag, and credentials are provisional and may change.
| Skill | What it does |
|---|---|
| azuresql-db-container | Start the Azure SQL Database engine locally the correct way: free-port selection, runtime-selected architecture, ready-wait retry loop, and CREATE DATABASE appdb provisioning. The foundation every other skill builds on. |
| azuresql-db-from-sql-server | Migrate a workflow off the SQL Server image (mcr.microsoft.com/mssql/server) onto the real cloud engine. Swaps the image, fixes the connection model, and verifies EngineEdition=5 / Edition='SQL Azure'. |
| azuresql-db-local-to-cloud | Take a database that works against the local engine and move it to Azure SQL Database in the cloud. Because it is the same engine, parity is the default, not a porting exercise. |
| azuresql-db-schema-migration | Apply and version schema changes against the engine: idempotent DDL, ordered migration scripts, run against appdb (never master). |
| azuresql-db-import | Load data into appdb after provisioning: bulk and script-based import. Does not rely on auto-run init directories (that convention is not honored here). |
| azuresql-db-rag | Build retrieval-augmented generation on the engine's native VECTOR(n) type and VECTOR_DISTANCE('cosine', a, b), using full-scan top-k for a small corpus and a DiskANN vector index once a full scan starts to hurt. |
| azuresql-db-ci | Run the engine in continuous integration: ephemeral container, ready-wait, provision, seed, test, tear down. Fails closed on the wrong image. |
| azuresql-db-sidecar | Run the engine as a sidecar alongside an app (compose-style), with runtime-selected architecture and a single SQL_CONNECTION_STRING contract. |
| azuresql-db-scaffold | Scaffold a new app wired to the engine: connection string via one SQL_CONNECTION_STRING env var, provisioning step, and seed step in the correct order. |
| azuresql-db-dab | Stand up an instant no-code REST + GraphQL API over the engine with Data API Builder (DAB): dab init/add/start, @env() connection, entities and relationships. Also serves DAB's built-in MCP endpoint (a DAB API surface, not a standalone SQL MCP server). |
| azuresql-db-functions | Build a serverless API and event-driven handlers with Azure Functions + the Azure SQL bindings: HTTP CRUD via input/output bindings, and the SQL trigger (Change Tracking) as the local event-driven mechanism. CES is cloud-only. |
| azuresql-db-seed | Populate the local dev database with realistic sample/test data: multi-table inserts in foreign-key order, generating N rows, and per-stack seeders (T-SQL + bcp/BULK INSERT, Node/Python fake data). |
| azuresql-db-testing | Integration-test in code against a real engine spun up per test with Testcontainers (.NET/Node/Python/Java), then torn down. Distinct from the CI-pipeline skill. |
| azuresql-db-connections | Make app connections reliable: connection pooling plus retry / transient-fault handling per stack, so the same code survives Azure SQL Database in the cloud. |
| azuresql-db-auth | Connect the app with a least-privilege database user instead of sa, pick the right auth method per environment (SQL locally, Microsoft Entra or managed identity in the cloud), secure the connection, and keep the secret out of source. |
| azuresql-db-faq | Answer questions about what the container can and cannot do, and why it differs from the cloud (backups, USE, vector index, GUI tooling, registry). Sorts each into engine vs. managed-service vs. SQL Server, and links the live Known limitations. |
| azuresql-db-feedback | Report a bug or request a feature without leaving the agent. Builds a complete, prefilled GitHub issue from context the agent already has (image tag, host OS, runtime, the failing command, the error), redacts secrets, and hands it to you to review and submit. It never submits anything without your explicit confirmation. |
These skills work in Claude Code, Codex, Cursor, and VS Code with GitHub Copilot. One folder format, all four tools. npx skills add works in every one; Claude Code and Codex additionally have a native plugin install with auto-update.
Claude Code: the native plugin (install + auto-update), or the portable command:
# in Claude Code:
/plugin marketplace add microsoft/azure-sql-database-container
/plugin install azure-sql-database-container@azure-sql-database-container
# or, anywhere:
npx skills add microsoft/azure-sql-database-containerCodex: the native plugin, or the portable command:
codex plugin marketplace add microsoft/azure-sql-database-container
codex plugin add azure-sql-database-container@azure-sql-database-container
# or:
npx skills add microsoft/azure-sql-database-containerCursor:
npx skills add microsoft/azure-sql-database-containerVS Code with GitHub Copilot. npx skills add writes to a folder Copilot already reads, so the skills are available with no extra step. Find them under Configure Chat → Skills (or type /skills in chat):
npx skills add microsoft/azure-sql-database-containerThe portable way. Works across agents that follow the skills.sh convention. The source is the repository, not a skill name:
npx skills add microsoft/azure-sql-database-containerInstall the whole collection unless you have a reason not to: the hub skill routes to the others, so a partial install loses the handoffs. Add --all to take every skill without prompting.
Name the skill you want:
npx skills add microsoft/azure-sql-database-container --skill <skill-name>| Skill | Install |
|---|---|
| azuresql-db-container | npx skills add microsoft/azure-sql-database-container --skill azuresql-db-container |
| azuresql-db-from-sql-server | npx skills add microsoft/azure-sql-database-container --skill azuresql-db-from-sql-server |
| azuresql-db-local-to-cloud | npx skills add microsoft/azure-sql-database-container --skill azuresql-db-local-to-cloud |
| azuresql-db-schema-migration | npx skills add microsoft/azure-sql-database-container --skill azuresql-db-schema-migration |
| azuresql-db-import | npx skills add microsoft/azure-sql-database-container --skill azuresql-db-import |
| azuresql-db-rag | npx skills add microsoft/azure-sql-database-container --skill azuresql-db-rag |
| azuresql-db-ci | npx skills add microsoft/azure-sql-database-container --skill azuresql-db-ci |
| azuresql-db-sidecar | npx skills add microsoft/azure-sql-database-container --skill azuresql-db-sidecar |
| azuresql-db-scaffold | npx skills add microsoft/azure-sql-database-container --skill azuresql-db-scaffold |
| azuresql-db-dab | npx skills add microsoft/azure-sql-database-container --skill azuresql-db-dab |
| azuresql-db-functions | npx skills add microsoft/azure-sql-database-container --skill azuresql-db-functions |
| azuresql-db-seed | npx skills add microsoft/azure-sql-database-container --skill azuresql-db-seed |
| azuresql-db-testing | npx skills add microsoft/azure-sql-database-container --skill azuresql-db-testing |
| azuresql-db-connections | npx skills add microsoft/azure-sql-database-container --skill azuresql-db-connections |
| azuresql-db-auth | npx skills add microsoft/azure-sql-database-container --skill azuresql-db-auth |
| azuresql-db-faq | npx skills add microsoft/azure-sql-database-container --skill azuresql-db-faq |
| azuresql-db-feedback | npx skills add microsoft/azure-sql-database-container --skill azuresql-db-feedback |
Each skill stands alone: the load-bearing facts are deliberately repeated in every one, so a single-skill install is fully functional. What you lose is the routing, since the hub hands off to the others. Install the whole collection unless you have a reason not to.
This is the step worth not skipping:
ls .claude/skills/ # Claude Code; see the matrix below for other agentsYou should see the azuresql-db-* directories. If the directory is missing or empty while .agents/skills/ is populated, the installer did not target your agent, and it can report success when this happens. Re-run it naming your agent explicitly:
npx skills add microsoft/azure-sql-database-container -a claude-codeIf they still do not appear, copy them across by hand:
mkdir -p .claude/skills && cp -R .agents/skills/azuresql-db-* .claude/skills/This is a known installer issue (vercel-labs/skills#1355, #744), not a problem with the skills. It is not specific to Windows.
Equally supported, and immune to the above. Drop each skill directory into your agent's skills folder (see the matrix), for example for Claude Code at the root of your project, or ~/.claude/skills/ to make it available everywhere:
mkdir -p .claude/skills
cp -R skills/azuresql-db-* .claude/skills/Same skills, per-agent install location (mirrors how Google, Supabase, and Neon ship their collections):
| Agent | Install location |
|---|---|
| Claude Code | .claude/skills/ (project) or ~/.claude/skills/ (global) |
| GitHub Copilot (VS Code + CLI) | .github/skills/ (the VS Code extension and the Copilot CLI both read it) |
| Codex | ~/.codex/skills/ |
| Cursor | .cursor/skills/ (project) |
npx skills add targets the active agent automatically; the table above is for manual placement, and for knowing where to look when you verify.
These skills follow the published Agent Skills guidance rather than a house style invented here. If you are adding a skill or editing one, read these first:
- Skill authoring best practices (Anthropic): the primary reference. Descriptions, progressive disclosure, degrees of freedom, feedback loops, and the anti-patterns.
- Agent Skills open standard (spec on GitHub): the vendor-neutral format these skills conform to, so they load in Claude Code, GitHub Copilot, Codex, and Cursor without change.
- Evaluating skills (OpenAI): the approach behind how this collection is tested, in particular testing whether a skill triggers on a realistic user request, and using negative controls to catch a skill that fires when it should not.
Conventions this collection holds itself to:
| Convention | Why |
|---|---|
Frontmatter is name and description, nothing else |
Anything else is agent-specific and breaks portability |
| Descriptions are third person, and name concrete trigger phrases | The description is a trigger signal for the model, not documentation for a human. Inconsistent voice degrades skill selection |
SKILL.md bodies stay under 500 lines |
Detail belongs in references/, which is read only when needed |
Reference files are linked as real relative markdown links, one level deep from SKILL.md |
Agents follow links; they do not reliably follow prose mentions or bare filenames |
| A skill never references a path outside its own folder | Skills install independently. A path into a sibling skill's folder resolves to nothing |
Reference files over 100 lines start with a ## Contents list |
An agent that previews a long file with a partial read still sees the full scope |
| Every skill stands alone, even where that means repeating a canonical fact | A user may install one skill, not the collection. Duplication is deliberate; drift is guarded by an automated check that the shared facts agree across all skills |
Each skill ends by pointing at azuresql-db-feedback if its own instructions failed |
A skill that quietly gets worked around is a bug we would otherwise never hear about |
Each skill carries a skill.spec.jsonc beside its SKILL.md. It is not installed with the skill and
it is not read by any agent. It is the authoring record, and its maturity field says how much has
actually been run against the skill, decided from evidence rather than from how finished it feels.
| Value | Means | Count today |
|---|---|---|
draft |
Nothing has run that could have contradicted it | 4 |
preview |
Its probes ran against a real engine and passed | 13 |
ga |
preview, plus the value question settled |
0 |
Evidence sets the ceiling. An author may declare below it and nobody may declare above it.
The probes live in each sidecar under validation.probes, each with the claim in the body it
defends. The four at draft are there for missing probe evidence and not for anything they got
wrong: azuresql-db-dab and azuresql-db-sidecar have probes that never reach a database,
azuresql-db-local-to-cloud declares both targets and has only ever run against the container, and
azuresql-db-feedback has a single HTTPS check that covers almost none of the skill.
The third rung asks whether a skill changes an answer, which is normally settled by running one
task twice, once with the skill and once without. Every sidecar here carries a value_declaration
recording that for this collection, that question was answered by a written argument instead, on
4 September 2026.
It is a declaration, not a measurement, and it is never reported as one. The reason it is allowed here and nowhere else is that the Azure SQL Database container is a gated private preview. No model has training data on the product, so the arm running without the skill would fail for the least interesting reason available: it has never heard of the thing.
The argument does not cover a whole skill, which is why each block carries both covers and
does_not_cover. It reaches the corrections no training data contains, such as Msg 40508,
Msg 12824, Msg 12713, Msg 40510, the absent /docker-entrypoint-initdb.d, the engine never
creating a database on connect, and the vector surface. It reaches none of the generic material
wrapped around them, such as retry with backoff, Compose YAML, workflow service containers or ORM
scaffolding, and whether these skills improve an answer there is unmeasured.
So no skill here is marked ga, and that is deliberate. The declaration raises the ceiling, and
all seventeen sit below it on purpose. Marking a skill generally available for a product that is not
generally available would read as a claim about the product, and the argument that earns the rung is
itself an argument from the product being pre-release. The 13 stay at preview and the 4 stay at
draft until the product moves.
Every declaration expires when the container reaches Public Preview. At that point training data
begins to contain the product, the premise stops holding, and all seventeen need revisiting. That is
recorded in expires_when on every sidecar, as a fixed token rather than prose, so a check can find
it: the-container-reaches-public-preview.
Every skill in this collection carries its knowledge in the same three layers, following Anthropic's progressive disclosure model. The layers are uniform across all skills; no skill is special.
| Layer | Where | Loaded | Purpose |
|---|---|---|---|
| 1. Instructions | SKILL.md body |
when the skill triggers | The happy path plus the canonical facts. Kept under 500 lines. |
| 2. References | references/*.md (linked one level deep) |
on demand | Deeper detail. For any feature the agent must generate a config or spec for, this includes a curated distilled shape and the version-pinned authoritative schema, so generation is correct and offline-reliable. |
| 3. Live docs (optional) | the Microsoft Learn MCP | when available at runtime | The current Microsoft documentation and schema, fetched on demand. Referenced by fully-qualified tool name and always with a fallback, so the skill still works when the MCP or the network is absent. |
Rules this enforces:
- Configs are generated against the latest schema. A feature that emits a config (for example
dab-config.json,host.json,schema.prisma, a compose file, a workflow) bundles the distilled shape and pins the schema in Layer 2, and points at the Learn MCP in Layer 3 for the current version. The distilled, pinned copy is the offline source of truth; the MCP keeps it current when reachable. - The MCP is optional, never a dependency. Layer 3 is phrased conditionally and always names the tool in
the fully-qualified form Anthropic requires (
mcp__microsoft-learn__microsoft_docs_fetch,mcp__microsoft-learn__microsoft_docs_search). If it is not configured, Layer 2 is authoritative. See Using the Microsoft Learn MCP to enable it. - No time-sensitive text and no skill-to-skill dependency, per the standard: each skill stands alone and reaches the same three layers on its own.
Every SKILL.md surfaces Layers 2 and 3 in a uniform "Staying current" section.
Layer 3 above is the Microsoft Learn MCP server: a public, no-auth, generally available server that returns current Microsoft documentation (Azure SQL, Data API Builder, Azure Functions, EF Core, T-SQL, SqlPackage, and the rest of Microsoft Learn). It is optional and the skills work without it, but enabling it lets an agent pull the latest reference and schema on demand.
To enable it in Claude Code, add the server to your project's .mcp.json:
{
"mcpServers": {
"microsoft-learn": {
"type": "http",
"url": "https://learn.microsoft.com/api/mcp"
}
}
}Other agents (GitHub Copilot, Codex, Cursor) accept the same type: http / url entry in their own MCP
config. Once enabled, the skills reference its tools as mcp__microsoft-learn__microsoft_docs_search,
mcp__microsoft-learn__microsoft_docs_fetch, and mcp__microsoft-learn__microsoft_code_sample_search. The
server label (microsoft-learn) is yours to choose; the fully-qualified tool prefix follows whatever you pick.
Every skill in this collection holds these facts true. If a generated workflow contradicts any of them, it is wrong.
-
Image:
sqldbpreview-dpgaeqhmgphzd4bk.azurecr.io/azure-sql/db-dev:latest(multi-architecture: linux/amd64 and linux/arm64, private preview registry). Sign in first:docker login sqldbpreview-dpgaeqhmgphzd4bk.azurecr.io -u <username>(enter the password when prompted). It is notmcr.microsoft.com/mssql/server.Note: the registry username and password are provided when you sign up for the Private Preview at https://aka.ms/sqldbcontainerpreview-signup. They are shared and pull-only, must be treated as secrets (do not redistribute), and may be rotated during the preview.
-
EULA:
ACCEPT_EULA=Yis required. -
Password: a complex
MSSQL_SA_PASSWORD(8+ chars, upper/lower/digit/symbol) is required. -
Port: the engine listens on 1433.
-
Identity:
SERVERPROPERTY('EngineEdition')= 5,SERVERPROPERTY('Edition')= 'SQL Azure'.
The image supports linux/amd64 and linux/arm64; Docker and Compose select the matching architecture automatically. Set --platform linux/amd64 (Docker) or platform: linux/amd64 (Compose) only to explicitly test x64 emulation.
- The engine does not auto-create databases on connect. Run
CREATE DATABASE appdbon a master connection before connecting withDatabase=appdb.appdbis just the example name used throughout these skills; the name is yours to choose, so substitute your project's database name in a real project. - Avoid
USEto switch databases. In a user-database session (the Azure-faithful context where you develop),USEreturnsMsg 40508, exactly as in Azure SQL Database in the cloud. Amasterconnection is a provisioning session where the Azure statement filter is not enforced, soUSEappears to work there, butmasteris for provisioning only, not application work. Always select the target database in the connection string (Database=appdb, or-d appdbfor sqlcmd). - A
masterconnection is for provisioning only. Do real work on the user database.
The engine is not ready the instant docker run returns. Wait with a retry loop using sqlcmd -C -b -l 2 (the -b makes a SQL error set the exit code, so transient startup errors like Msg 913 are retried, not masked) and provision appdb inside that same loop. Never poll bare sqlcmd without -l.
The image does not auto-run /docker-entrypoint-initdb.d/*.sql. That is a Postgres/MySQL convention and is not honored here. Seed by running sqlcmd -d appdb -i seed.sql after provisioning appdb.
Standardize on:
Server=localhost,1433;Database=appdb;User Id=sa;Password=...;TrustServerCertificate=true
House style spells the keywords User Id= / Password= / Database=, so every example reads the same way. Uid= and Pwd= are documented SqlClient synonyms and work too; ODBC strings use ODBC's own Uid= / Pwd=. For sqlcmd, pass -C to trust the self-signed cert. Apps read the connection string from a single SQL_CONNECTION_STRING env var.
Native VECTOR(n) column type and VECTOR_DISTANCE('cosine', a, b). Insert with CAST(CAST(? AS NVARCHAR(MAX)) AS VECTOR(n)) where n is a literal, never a bind parameter (a parameter dimension fails with "Incorrect syntax near '@P3'"). The inner CAST(? AS NVARCHAR(MAX)) is required because a real embedding's JSON string (~16 KB for 768 dims) exceeds the driver's 4000-char threshold and is otherwise sent as ntext, which the engine rejects ("Explicit conversion from data type ntext to vector is not allowed (529)"). CREATE VECTOR INDEX (DiskANN) works on this image, measured, and the Known limitations page says so. It needs SET QUOTED_IDENTIFIER ON and at least 100 rows with non-null vectors (Msg 42266 below that). Full-scan top-k stays exact and stays the right choice for a small table. The azuresql-db-rag skill carries the rules the index imposes.
Free port + runtime-selected architecture + ready-wait + provision appdb:
# Pick a free host port (works in bash and zsh).
HOST_PORT=1433; while lsof -nP -iTCP:"$HOST_PORT" -sTCP:LISTEN >/dev/null 2>&1; do HOST_PORT=$((HOST_PORT+1)); done
MSSQL_SA_PASSWORD="${MSSQL_SA_PASSWORD:-Aa1%$(openssl rand -hex 16)}"
docker rm -f sqldb 2>/dev/null
docker run -d --name sqldb -e "ACCEPT_EULA=Y" -e "MSSQL_SA_PASSWORD=$MSSQL_SA_PASSWORD" \
-p "127.0.0.1:$HOST_PORT:1433" sqldbpreview-dpgaeqhmgphzd4bk.azurecr.io/azure-sql/db-dev:latest
until docker exec sqldb /opt/mssql-tools18/bin/sqlcmd -S localhost -U sa -P "$MSSQL_SA_PASSWORD" -C -b -l 2 \
-Q "IF DB_ID('appdb') IS NULL CREATE DATABASE appdb;" >/dev/null 2>&1; do sleep 2; done
echo "ready on localhost,$HOST_PORT"