Chapter Navigation:
- 📚 Course Home: AZD For Beginners
- 📖 Current Chapter: Chapter 3 - Configuration & Authentication
- ⬅️ Previous: Your First Project
- ➡️ Next: Deployment Guide
- 🚀 Next Chapter: Chapter 4: Infrastructure as Code
This comprehensive guide covers all aspects of configuring Azure Developer CLI for optimal development and deployment workflows. You'll learn about the configuration hierarchy, environment management, authentication methods, and advanced configuration patterns that enable efficient and secure Azure deployments.
By the end of this lesson, you will:
- Master the azd configuration hierarchy and understand how settings are prioritized
- Configure global and project-specific settings effectively
- Manage multiple environments with different configurations
- Implement secure authentication and authorization patterns
- Understand advanced configuration patterns for complex scenarios
After completing this lesson, you will be able to:
- Configure azd for optimal development workflows
- Set up and manage multiple deployment environments
- Implement secure configuration management practices
- Troubleshoot configuration-related issues
- Customize azd behavior for specific organizational requirements
This comprehensive guide covers all aspects of configuring Azure Developer CLI for optimal development and deployment workflows.
If you're new to AI agents, here's a simple way to think about them within the azd world.
An agent is a piece of software that can receive a request, reason about it, and take actions—often by calling an AI model, looking up data, or invoking other services. In an azd project, an agent is just another service alongside your web frontend or API backend.
An azd project is made up of three layers: infrastructure, code, and configuration. Agents plug into these layers the same way any other service does:
| Layer | What It Does for a Traditional App | What It Does for an Agent |
|---|---|---|
Infrastructure (infra/) |
Provisions a web app and database | Provisions an AI model endpoint, search index, or agent host |
Code (src/) |
Contains your frontend and API source code | Contains your agent logic and prompt definitions |
Configuration (azure.yaml) |
Lists your services and their hosting targets | Lists your agent as a service, pointing to its code and host |
You don't need to memorize the syntax right now. Conceptually, azure.yaml is the file where you tell azd: "Here are the services that make up my application, and here's where to find their code."
When your project includes an AI agent, azure.yaml simply lists that agent as one of the services. azd then knows to provision the right infrastructure (like an Microsoft Foundry Models endpoint or a Container App to host the agent) and deploy your agent code—just as it would for a web app or API.
This means there's nothing fundamentally new to learn. If you understand how azd manages a web service, you already understand how it manages an agent.
azd uses a hierarchical configuration system:
- Command-line flags (highest priority)
- Environment variables
- Local project configuration (
.azd/config.json) - Global user configuration (
~/.azd/config.json) - Default values (lowest priority)
# Set default subscription
azd config set defaults.subscription "12345678-1234-1234-1234-123456789abc"
# Set default location
azd config set defaults.location "eastus2"
# Set default resource group naming convention
azd config set defaults.resourceGroupName "rg-{env-name}-{location}"
# View all global configuration
azd config show
# Remove a configuration
azd config unset defaults.location# Development preferences
azd config set alpha.enable true # Enable alpha features
azd config set telemetry.enabled false # Disable telemetry
azd config set output.format json # Set output format
# Security settings
azd config set auth.useAzureCliCredential true # Use Azure CLI for auth
azd config set tls.insecure false # Enforce TLS verification
# Performance tuning
azd config set provision.parallelism 5 # Parallel resource creation
azd config set deploy.timeout 30m # Deployment timeoutThe azure.yaml file is the heart of your azd project:
# Minimum configuration
name: my-awesome-app
metadata:
template: my-template@1.0.0
templateBranch: main
# Service definitions
services:
# Frontend service
web:
project: ./src/web # Source code location
language: js # Programming language
host: appservice # Azure service type
dist: dist # Build output directory
# Backend API service
api:
project: ./src/api
language: python
host: containerapp
docker:
context: ./src/api
dockerfile: Dockerfile
# Database service
database:
project: ./src/db
host: postgres
# Infrastructure configuration
infra:
provider: bicep # Infrastructure provider
path: ./infra # Infrastructure code location
parameters:
environmentName: ${AZURE_ENV_NAME}
location: ${AZURE_LOCATION}
# Deployment hooks
hooks:
preprovision: # Before infrastructure deployment
shell: sh
run: |
echo "Preparing infrastructure..."
./scripts/validate-config.sh
postprovision: # After infrastructure deployment
shell: pwsh
run: |
Write-Host "Infrastructure deployed successfully"
./scripts/setup-database.ps1
predeploy: # Before application deployment
shell: sh
run: |
echo "Building application..."
npm run build
postdeploy: # After application deployment
shell: sh
run: |
echo "Running post-deployment tests..."
npm run test:integration
# Pipeline configuration
pipeline:
provider: github # CI/CD provider
variables:
- AZURE_CLIENT_ID
- AZURE_TENANT_ID
secrets:
- AZURE_CLIENT_SECRETservices:
web-static:
host: staticwebapp # Azure Static Web Apps
web-dynamic:
host: appservice # Azure App Service
api-containers:
host: containerapp # Azure Container Apps
api-functions:
host: function # Azure Functions
api-spring:
host: springapp # Azure Spring Appsservices:
node-app:
language: js
buildCommand: npm run build
startCommand: npm start
python-app:
language: python
buildCommand: pip install -r requirements.txt
startCommand: gunicorn app:app
dotnet-app:
language: csharp
buildCommand: dotnet build
startCommand: dotnet run
java-app:
language: java
buildCommand: mvn clean package
startCommand: java -jar target/app.jar# Create a new environment
azd env new development
# Create with specific location
azd env new staging --location "westus2"
# Create from template
azd env new production --subscription "prod-sub-id" --location "eastus"Each environment has its own configuration in .azure/<env-name>/config.json:
{
"version": 1,
"environmentName": "development",
"subscriptionId": "12345678-1234-1234-1234-123456789abc",
"location": "eastus2",
"resourceGroupName": "rg-myapp-dev-eastus2",
"services": {
"web": {
"resourceId": "/subscriptions/.../resourceGroups/.../providers/Microsoft.Web/sites/web-abc123",
"endpoints": ["https://web-abc123.azurewebsites.net"]
},
"api": {
"resourceId": "/subscriptions/.../resourceGroups/.../providers/Microsoft.App/containerApps/api-def456",
"endpoints": ["https://api-def456.azurecontainerapps.io"]
}
}
}# Set environment-specific variables
azd env set DATABASE_URL "postgresql://user:pass@host:5432/db"
azd env set API_KEY "secret-api-key"
azd env set DEBUG "true"
# View environment variables
azd env get-values
# Expected output:
# DATABASE_URL=postgresql://user:pass@host:5432/db
# API_KEY=secret-api-key
# DEBUG=true
# Remove environment variable
azd env unset DEBUG
# Verify removal
azd env get-values | grep DEBUG
# (should return nothing)Create .azure/env.template for consistent environment setup:
# Required variables
AZURE_SUBSCRIPTION_ID=
AZURE_LOCATION=
# Application settings
DATABASE_NAME=
API_BASE_URL=
STORAGE_ACCOUNT_NAME=
# Optional development settings
DEBUG=false
LOG_LEVEL=info# Use Azure CLI credentials (default)
azd config set auth.useAzureCliCredential true
# Login with specific tenant
az login --tenant <tenant-id>
# Set default subscription
az account set --subscription <subscription-id>For CI/CD pipelines:
# Set environment variables
export AZURE_CLIENT_ID="your-client-id"
export AZURE_CLIENT_SECRET="your-client-secret"
export AZURE_TENANT_ID="your-tenant-id"
# Or configure directly
azd config set auth.clientId "your-client-id"
azd config set auth.tenantId "your-tenant-id"For Azure-hosted environments:
# Enable managed identity authentication
azd config set auth.useMsi true
azd config set auth.msiClientId "your-managed-identity-client-id"Configure infrastructure parameters in infra/main.parameters.json:
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"environmentName": {
"value": "${AZURE_ENV_NAME}"
},
"location": {
"value": "${AZURE_LOCATION}"
},
"appServiceSkuName": {
"value": "B1"
},
"databaseSkuName": {
"value": "Standard_B1ms"
}
}
}For Terraform projects, configure in infra/terraform.tfvars:
environment_name = "${AZURE_ENV_NAME}"
location = "${AZURE_LOCATION}"
app_service_sku = "B1"
database_sku = "GP_Gen5_2"# In azure.yaml
services:
web:
project: ./src/web
language: js
buildCommand: npm run build:prod
buildEnvironment:
NODE_ENV: production
REACT_APP_API_URL: ${API_URL}
dist: build
api:
project: ./src/api
language: python
buildCommand: |
pip install -r requirements.txt
python -m pytest tests/
buildEnvironment:
PYTHONPATH: srcservices:
api:
project: ./src/api
host: containerapp
docker:
context: ./src/api
dockerfile: Dockerfile
target: production
buildArgs:
NODE_ENV: production
API_VERSION: v1.0.0Example Dockerfile: https://github.com/Azure-Samples/deepseek-go/blob/main/azure.yaml
# Set naming conventions
azd config set naming.resourceGroup "rg-{project}-{env}-{location}"
azd config set naming.storageAccount "{project}{env}sa"
azd config set naming.keyVault "kv-{project}-{env}"# In azure.yaml
infra:
provider: bicep
parameters:
vnetAddressPrefix: "10.0.0.0/16"
subnetAddressPrefix: "10.0.1.0/24"
enablePrivateEndpoints: true# In azure.yaml
monitoring:
applicationInsights:
enabled: true
samplingPercentage: 100
logAnalytics:
enabled: true
retentionDays: 30# .azure/development/.env
DEBUG=true
LOG_LEVEL=debug
ENABLE_HOT_RELOAD=true
MOCK_EXTERNAL_APIS=true# .azure/staging/.env
DEBUG=false
LOG_LEVEL=info
ENABLE_MONITORING=true
USE_PRODUCTION_APIS=true# .azure/production/.env
DEBUG=false
LOG_LEVEL=error
ENABLE_MONITORING=true
ENABLE_SECURITY_HEADERS=true# Check configuration syntax
azd config validate
# Test environment variables
azd env get-values
# Validate infrastructure
azd provision --dry-runCreate validation scripts in scripts/:
#!/bin/bash
# scripts/validate-config.sh
echo "Validating configuration..."
# Check required environment variables
if [ -z "$AZURE_SUBSCRIPTION_ID" ]; then
echo "Error: AZURE_SUBSCRIPTION_ID not set"
exit 1
fi
# Validate azure.yaml syntax
if ! azd config validate; then
echo "Error: Invalid azure.yaml configuration"
exit 1
fi
echo "Configuration validation passed!"# Good: Use environment variables
database:
connectionString: ${DATABASE_CONNECTION_STRING}
# Avoid: Hardcode sensitive values
database:
connectionString: "Server=myserver;Database=mydb;User=myuser;Password=mypassword".azure/
├── config.json # Global project config
├── env.template # Environment template
├── development/
│ ├── config.json # Dev environment config
│ └── .env # Dev environment variables
├── staging/
│ ├── config.json # Staging environment config
│ └── .env # Staging environment variables
└── production/
├── config.json # Production environment config
└── .env # Production environment variables
# .gitignore
.azure/*/config.json # Environment configs (contain resource IDs)
.azure/*/.env # Environment variables (may contain secrets)
.env # Local environment fileDocument your configuration in CONFIG.md:
# Configuration Guide
## Required Environment Variables
- `DATABASE_CONNECTION_STRING`: Connection string for the database
- `API_KEY`: API key for external service
- `STORAGE_ACCOUNT_KEY`: Azure Storage account key
## Environment-Specific Settings
- Development: Uses local database, debug logging enabled
- Staging: Uses staging database, info logging
- Production: Uses production database, error logging onlyGoal: Create and configure three environments with different settings
# Create development environment
azd env new dev
azd env set LOG_LEVEL debug
azd env set ENABLE_TELEMETRY false
azd env set APP_INSIGHTS_SAMPLING 100
# Create staging environment
azd env new staging
azd env set LOG_LEVEL info
azd env set ENABLE_TELEMETRY true
azd env set APP_INSIGHTS_SAMPLING 50
# Create production environment
azd env new production
azd env set LOG_LEVEL error
azd env set ENABLE_TELEMETRY true
azd env set APP_INSIGHTS_SAMPLING 10
# Verify each environment
azd env select dev && azd env get-values
azd env select staging && azd env get-values
azd env select production && azd env get-valuesSuccess Criteria:
- Three environments created successfully
- Each environment has unique configuration
- Can switch between environments without errors
-
azd env listshows all three environments
Goal: Practice secure configuration with sensitive data
# Set secrets (not displayed in output)
azd env set DB_PASSWORD "$(openssl rand -base64 32)" --secret
azd env set API_KEY "sk-$(openssl rand -hex 16)" --secret
# Set non-secret config
azd env set DB_HOST "mydb.postgres.database.azure.com"
azd env set DB_NAME "production_db"
# View environment (secrets should be redacted)
azd env get-values
# Verify secrets are stored
azd env get DB_PASSWORD # Should show actual valueSuccess Criteria:
- Secrets stored without displaying in terminal
-
azd env get-valuesshows redacted secrets - Individual
azd env get <SECRET_NAME>retrieves actual value
- Your First Project - Apply configuration in practice
- Deployment Guide - Use configuration for deployment
- Provisioning Resources - Production-ready configurations
Chapter Navigation:
- 📚 Course Home: AZD For Beginners
- 📖 Current Chapter: Chapter 3 - Configuration & Authentication
- ⬅️ Previous: Your First Project
- ➡️ Next Chapter: Chapter 4: Infrastructure as Code
- Next Lesson: Your First Project