azure-data-api-builder
Deploy Data API Builder (DAB) to Azure Container Apps with Azure SQL, Azure Container Registry (ACR), and Azure Developer CLI (azd). Produces Bicep templates, Dockerfile, and azure.yaml. Use when asked to deploy DAB to Azure, create Bicep for DAB, or set up cloud API hosting.
Best use case
azure-data-api-builder is best used when you need a repeatable AI agent workflow instead of a one-off prompt.
Deploy Data API Builder (DAB) to Azure Container Apps with Azure SQL, Azure Container Registry (ACR), and Azure Developer CLI (azd). Produces Bicep templates, Dockerfile, and azure.yaml. Use when asked to deploy DAB to Azure, create Bicep for DAB, or set up cloud API hosting.
Teams using azure-data-api-builder should expect a more consistent output, faster repeated execution, less prompt rewriting.
When to use this skill
- You want a reusable workflow that can be run more than once with consistent structure.
When not to use this skill
- You only need a quick one-off answer and do not need a reusable workflow.
- You cannot install or maintain the underlying files, dependencies, or repository context.
Installation
Claude Code / Cursor / Codex
Manual Installation
- Download SKILL.md from GitHub
- Place it in
.claude/skills/azure-data-api-builder/SKILL.mdinside your project - Restart your AI agent — it will auto-discover the skill
How azure-data-api-builder Compares
| Feature / Agent | azure-data-api-builder | Standard Approach |
|---|---|---|
| Platform Support | Not specified | Limited / Varies |
| Context Awareness | High | Baseline |
| Installation Complexity | Unknown | N/A |
Frequently Asked Questions
What does this skill do?
Deploy Data API Builder (DAB) to Azure Container Apps with Azure SQL, Azure Container Registry (ACR), and Azure Developer CLI (azd). Produces Bicep templates, Dockerfile, and azure.yaml. Use when asked to deploy DAB to Azure, create Bicep for DAB, or set up cloud API hosting.
Where can I find the source code?
You can find the source code on GitHub using the link provided at the top of the page.
SKILL.md Source
# Data API Builder — Azure Deployment
This skill covers deploying **Data API Builder (DAB)** to **Azure Container Apps** with **Azure SQL**, using **Azure Developer CLI (azd)** for orchestration.
For local development, see the `aspire-data-api-builder` or `docker-data-api-builder` skill.
---
## Core Mental Model
- **Always build a custom Docker image** with `dab-config.json` baked in — never use volume mounts in Azure.
- **azd** orchestrates the full deployment: Bicep provisions resources, a post-provision hook deploys content.
- **ACR** hosts all custom images (DAB, web, Inspector).
- **Connection strings use secrets** — never plain-text env vars for credentials.
- **`TrustServerCertificate=true`** is required in all Azure SQL connection strings.
---
## Anti-Patterns (NEVER DO)
- ❌ Azure Files share mount for `dab-config.json`
- ❌ Azure Storage Account for config files
- ❌ Volume mounts in Azure Container Apps for DAB config
- ❌ Any external file storage for DAB config in cloud
- ✅ Custom Docker image with config embedded via `COPY`
**Why custom image?** Config is versioned with the image — immutable, reproducible, no extra infrastructure, faster startup, fewer failure modes.
---
## Architecture
```
azd up
├── Bicep provisions:
│ Azure SQL Server + Database
│ Azure Container Registry (ACR)
│ Container Apps Environment
│ DAB Container App (port 5000)
│ SQL Commander Container App (port 8080)
│ Web Container App (port 80)
│ MCP Inspector Container App (port 80)
│
└── post-provision.ps1:
1. Add client IP to SQL firewall
2. Build + deploy dacpac schema
3. Build custom DAB image (with CORS) → push to ACR
4. Update DAB container app
5. Build web image → push to ACR
6. Update web container app
7. Build Inspector image → push to ACR
8. Update Inspector container app
```
---
## File Structure
```
project/
├── azure.yaml # azd entry point
├── azure/
│ ├── main.bicep # Subscription-scoped entry
│ ├── resources.bicep # All Azure resources
│ └── post-provision.ps1 # Content deployment hook
├── api/
│ ├── dab-config.json # DAB configuration
│ └── Dockerfile # Custom DAB image
└── database/
├── database.sqlproj
├── Tables/*.sql
└── Scripts/PostDeployment.sql
```
---
## Templates
### Dockerfile (DAB Custom Image)
```dockerfile
FROM mcr.microsoft.com/azure-databases/data-api-builder:1.7.83-rc
COPY dab-config.json /App/dab-config.json
```
> Two lines. Config baked in. No volume mounts.
### azure.yaml
```yaml
name: my-project
metadata:
template: my-project
infra:
provider: bicep
path: azure
module: main
hooks:
postprovision:
shell: pwsh
continueOnError: false
interactive: true
run: ./azure/post-provision.ps1
```
### main.bicep (Subscription Scope)
```bicep
targetScope = 'subscription'
@minLength(1)
@maxLength(64)
param environmentName string
param location string
@secure()
param sqlAdminPassword string
param sqlAdminUser string = 'sqladmin'
var tags = { 'azd-env-name': environmentName }
param resourceToken string = ''
var effectiveToken = empty(resourceToken)
? uniqueString(subscription().id, environmentName, location)
: resourceToken
resource rg 'Microsoft.Resources/resourceGroups@2024-03-01' = {
name: 'rg-${environmentName}-${effectiveToken}'
location: location
tags: tags
}
module resources 'resources.bicep' = {
scope: rg
name: 'resources'
params: {
location: location
tags: tags
resourceToken: effectiveToken
sqlAdminUser: sqlAdminUser
sqlAdminPassword: sqlAdminPassword
}
}
// Outputs become env vars for post-provision hook
output AZURE_RESOURCE_GROUP string = rg.name
output AZURE_SQL_SERVER_NAME string = resources.outputs.sqlServerName
output AZURE_SQL_SERVER_FQDN string = resources.outputs.sqlServerFqdn
output AZURE_SQL_DATABASE string = 'sql-db'
output AZURE_SQL_ADMIN_USER string = sqlAdminUser
output AZURE_ACR_NAME string = resources.outputs.acrName
output AZURE_CONTAINER_APP_API_NAME string = resources.outputs.dabAppName
output AZURE_CONTAINER_APP_API_FQDN string = resources.outputs.dabFqdn
```
### resources.bicep — DAB Container App
The DAB container app definition within `resources.bicep`:
```bicep
param location string
param tags object
param resourceToken string
param sqlAdminUser string
@secure()
param sqlAdminPassword string
// ── SQL Server + Database ──
resource sqlServer 'Microsoft.Sql/servers@2023-08-01-preview' = {
name: 'sql-server-${resourceToken}'
location: location
tags: tags
properties: {
administratorLogin: sqlAdminUser
administratorLoginPassword: sqlAdminPassword
}
}
resource sqlFirewallAzure 'Microsoft.Sql/servers/firewallRules@2023-08-01-preview' = {
parent: sqlServer
name: 'AllowAzureServices'
properties: {
startIpAddress: '0.0.0.0'
endIpAddress: '0.0.0.0'
}
}
resource sqlDb 'Microsoft.Sql/servers/databases@2023-08-01-preview' = {
parent: sqlServer
name: 'sql-db'
location: location
tags: tags
sku: { name: 'Basic', tier: 'Basic' }
}
// ── Container Registry ──
resource acr 'Microsoft.ContainerRegistry/registries@2023-11-01-preview' = {
name: 'acr${resourceToken}'
location: location
tags: tags
sku: { name: 'Basic' }
properties: { adminUserEnabled: true }
}
// ── Container Apps Environment ──
resource cae 'Microsoft.App/managedEnvironments@2024-03-01' = {
name: 'environment-${resourceToken}'
location: location
tags: tags
properties: {}
}
// ── DAB Container App ──
var sqlConnString = 'Server=tcp:${sqlServer.properties.fullyQualifiedDomainName},1433;Database=sql-db;User Id=${sqlAdminUser};Password=${sqlAdminPassword};Encrypt=true;TrustServerCertificate=true'
resource dabApp 'Microsoft.App/containerApps@2024-03-01' = {
name: 'data-api-${resourceToken}'
location: location
tags: tags
properties: {
managedEnvironmentId: cae.id
configuration: {
ingress: {
external: true
targetPort: 5000
}
registries: [
{
server: acr.properties.loginServer
username: acr.listCredentials().username
passwordSecretRef: 'acr-password'
}
]
secrets: [
{ name: 'db-conn', value: sqlConnString }
{ name: 'acr-password', value: acr.listCredentials().passwords[0].value }
]
}
template: {
containers: [
{
name: 'dab-api'
image: 'mcr.microsoft.com/azure-databases/data-api-builder:1.7.83-rc'
resources: { cpu: json('0.5'), memory: '1Gi' }
env: [
{ name: 'MSSQL_CONNECTION_STRING', secretRef: 'db-conn' }
]
}
]
scale: { minReplicas: 1, maxReplicas: 1 }
}
}
}
// ── Outputs ──
output sqlServerName string = sqlServer.name
output sqlServerFqdn string = sqlServer.properties.fullyQualifiedDomainName
output acrName string = acr.name
output dabAppName string = dabApp.name
output dabFqdn string = dabApp.properties.configuration.ingress.fqdn
```
> **Note:** Bicep provisions with a placeholder image. The post-provision hook replaces it with the custom ACR image.
---
## Connection Strings
### Azure SQL (SQL Auth)
```
Server=tcp:<server>.database.windows.net,1433;Database=sql-db;User Id=sqladmin;Password=<password>;Encrypt=true;TrustServerCertificate=true
```
### Azure SQL (Managed Identity)
```
Server=tcp:<server>.database.windows.net,1433;Database=sql-db;Authentication=Active Directory Default;Encrypt=true;TrustServerCertificate=true
```
> **CRITICAL:** `TrustServerCertificate=true` is required — DAB and SQL Commander will not connect without it.
---
## CORS Configuration
DAB's `dab-config.json` needs the web app's Azure origin in its CORS config. Use a placeholder that gets replaced during image build:
### dab-config.json (with placeholder)
```json
"cors": {
"origins": ["http://localhost:5173", "__WEB_URL_AZURE__"],
"allow-credentials": false
}
```
### Replacement in post-provision.ps1
```powershell
$webOrigin = "https://$webFqdn"
$dabConfig = Get-Content -Path "api/dab-config.json" -Raw
$dabConfig = $dabConfig.Replace("__WEB_URL_AZURE__", $webOrigin)
$dabConfig | Out-File -FilePath "api/dab-config.json" -Encoding utf8 -Force
```
> This replacement happens before `az acr build`, so the correct origin is baked into the image.
---
## Post-Provision Hook Pattern
The `post-provision.ps1` script runs after Bicep provisions all resources. It handles content that can't be done declaratively:
```powershell
$ErrorActionPreference = "Stop"
# Variables from Bicep outputs (set by azd as env vars)
$resourceGroup = $env:AZURE_RESOURCE_GROUP
$sqlServerName = $env:AZURE_SQL_SERVER_NAME
$sqlServerFqdn = $env:AZURE_SQL_SERVER_FQDN
$sqlDb = $env:AZURE_SQL_DATABASE
$sqlAdminUser = $env:AZURE_SQL_ADMIN_USER
$sqlAdminPassword = $env:AZURE_SQL_ADMIN_PASSWORD
$acrName = $env:AZURE_ACR_NAME
$dabAppName = $env:AZURE_CONTAINER_APP_API_NAME
$dabFqdn = $env:AZURE_CONTAINER_APP_API_FQDN
$sqlConn = "Server=tcp:$sqlServerFqdn,1433;Database=$sqlDb;User Id=$sqlAdminUser;Password=$sqlAdminPassword;Encrypt=true;TrustServerCertificate=true"
# ── 1. Open SQL firewall for local machine ──
$myIp = (Invoke-WebRequest -Uri "https://api.ipify.org" -UseBasicParsing).Content
az sql server firewall-rule create `
--resource-group $resourceGroup `
--server $sqlServerName `
--name "azd-deploy-client" `
--start-ip-address $myIp `
--end-ip-address $myIp 2>$null | Out-Null
# ── 2. Deploy database schema (dacpac) ──
dotnet build database/database.sqlproj -c Release
sqlpackage /Action:Publish `
/SourceFile:database/bin/Release/database.dacpac `
/TargetConnectionString:"$sqlConn" `
/p:BlockOnPossibleDataLoss=false
# ── 3. Build custom DAB image with CORS → push to ACR ──
$apiDeployDir = "api-deploy-temp"
Copy-Item -Path "api" -Destination $apiDeployDir -Recurse -Force
$webOrigin = "https://$env:AZURE_WEB_APP_FQDN"
$dabConfig = Get-Content -Path "$apiDeployDir/dab-config.json" -Raw
$dabConfig = $dabConfig.Replace("__WEB_URL_AZURE__", $webOrigin)
$dabConfig | Out-File -FilePath "$apiDeployDir/dab-config.json" -Encoding utf8 -Force
az acr build --registry $acrName --image dab-api:latest --file "$apiDeployDir/Dockerfile" $apiDeployDir/
Remove-Item $apiDeployDir -Recurse -Force
# ── 4. Update DAB container app with custom image ──
az containerapp update `
--name $dabAppName `
--resource-group $resourceGroup `
--image "$acrName.azurecr.io/dab-api:latest"
```
> Steps 5-8 handle web app, Inspector — see `azure-mcp-inspector` and `azure-sql-commander` skills.
---
## Deployment Commands
### Full deployment (recommended)
```powershell
azd up
```
This runs Bicep provisioning + post-provision hook in one command.
### Re-deploy DAB only (after config change)
```powershell
# Replace CORS placeholder
$dabConfig = Get-Content -Path "api/dab-config.json" -Raw
$dabConfig = $dabConfig.Replace("__WEB_URL_AZURE__", $webOrigin)
$dabConfig | Out-File -FilePath "api-deploy-temp/dab-config.json" -Encoding utf8
# Build and push
az acr build --registry <acr-name> --image dab-api:latest --file api/Dockerfile api/
# Update container
az containerapp update --name <app-name> --resource-group <rg> --image <acr>.azurecr.io/dab-api:latest
```
### Re-deploy schema only
```powershell
dotnet build database/database.sqlproj -c Release
sqlpackage /Action:Publish `
/SourceFile:database/bin/Release/database.dacpac `
/TargetConnectionString:"Server=tcp:<fqdn>,1433;Database=sql-db;User Id=sqladmin;Password=<pw>;Encrypt=true;TrustServerCertificate=true" `
/p:BlockOnPossibleDataLoss=false
```
---
## Verification
After deployment, verify DAB is healthy:
```powershell
$r = Invoke-WebRequest -Uri "https://<dab-fqdn>/health" -UseBasicParsing
$r.StatusCode # Should be 200
```
Also check:
- REST: `https://<dab-fqdn>/api/<entity>`
- GraphQL: `https://<dab-fqdn>/graphql`
- MCP: `https://<dab-fqdn>/mcp`
- Swagger: `https://<dab-fqdn>/swagger`
---
## Common Issues
### DAB container fails to start
- Check connection string secret is correct in Container Apps
- Verify Azure SQL firewall allows Azure services (`0.0.0.0` rule)
- Check `TrustServerCertificate=true` is in the connection string
### Schema not found (404 on entities)
- Database schema must be deployed **before** the DAB image is built
- Post-provision runs dacpac first, then builds the DAB image — this order matters
### CORS errors from web app
- The `__WEB_URL_AZURE__` placeholder must be replaced before `az acr build`
- Verify the replacement happened: check post-provision output for "CORS origin set to..."
- After adding a new web origin, rebuild and push the DAB image
### ACR build fails
- Verify ACR admin is enabled: `az acr show --name <acr> --query adminUserEnabled`
- Check Dockerfile path is correct relative to build context
### Container app shows old image
- Azure caches images. After pushing, update the container:
```powershell
az containerapp update --name <app> --resource-group <rg> --image <acr>.azurecr.io/dab-api:latest
```
---
## Key Differences: Local vs Azure
| Aspect | Local (Docker/Aspire) | Azure |
|--------|----------------------|-------|
| **Config mount** | Bind mount `:ro` | Baked into image |
| **Connection** | `Server=sql-2025` (service name) | `Server=tcp:<fqdn>,1433` |
| **CORS** | `*` or `localhost` | Specific `https://` origin |
| **Secrets** | `.env` file | Container Apps secrets |
| **Schema deploy** | `sqlpackage` to `localhost` | `sqlpackage` to Azure SQL FQDN |
| **Image source** | Docker Hub / MCR direct | ACR (custom image) |
---
## Related Skills
- **`aspire-data-api-builder`** — Local dev with .NET Aspire
- **`docker-data-api-builder`** — Local dev with Docker Compose
- **`data-api-builder-config`** — DAB config file reference
- **`data-api-builder-cli`** — DAB CLI commands
- **`azure-sql-commander`** — Deploy SQL Commander to Azure
- **`azure-mcp-inspector`** — Deploy MCP Inspector to AzureRelated Skills
azure-storage-file-share-py
Azure Storage File Share SDK for Python. Use for SMB file shares, directories, and file operations in the cloud.
azure-storage-blob-rust
Azure Blob Storage SDK for Rust. Use for uploading, downloading, and managing blobs and containers.
azure-servicebus-py
Azure Service Bus SDK for Python messaging. Use for queues, topics, subscriptions, and enterprise messaging patterns.
azure-servicebus-dotnet
Azure Service Bus SDK for .NET. Enterprise messaging with queues, topics, subscriptions, and sessions.
azure-search-documents-py
Azure AI Search SDK for Python. Use for vector search, hybrid search, semantic ranking, indexing, and skillsets.
azure-search-documents-dotnet
Azure AI Search SDK for .NET (Azure.Search.Documents). Use for building search applications with full-text, vector, semantic, and hybrid search.
azure-resource-manager-durabletask-dotnet
Azure Resource Manager SDK for Durable Task Scheduler in .NET.
azure-prepare
Default entry point for Azure application development EXCEPT cross-cloud migration — use azure-cloud-migrate instead. Analyzes your project and prepares it for Azure deployment by generating infrastructure code (Bicep/Terraform), azure.yaml, and Dockerfiles. WHEN: "create an app", "build a web app", "create API", "create frontend", "create backend", "add a feature", "build a service", "develop a project", "modernize my code", "update my application", "add database", "add authentication", "add caching", "deploy to Azure", "host on Azure", "Azure with terraform", "Azure with azd", "generate azure.yaml", "generate Bicep", "generate Terraform", "create Azure Functions app", "create serverless HTTP API", "create function app", "create event-driven function", "create and deploy to Azure", "create Azure Functions and deploy", "create function app and deploy".
azure-pipelines
Use when validating Azure DevOps pipeline changes for the VS Code build. Covers queueing builds, checking build status, viewing logs, and iterating on pipeline YAML changes without waiting for full CI runs.
azure-pipelines-validator
Comprehensive toolkit for validating, linting, and securing Azure DevOps Pipeline configurations.
azure-pipelines-generator
Comprehensive toolkit for generating best practice Azure DevOps Pipelines following current standards and conventions. Use this skill when creating new Azure Pipelines, implementing CI/CD workflows, or building deployment pipelines.
azure-networking
Configure Azure VNet, NSG, Load Balancer, and network topology.