Imagine packing for a trip — you only bring a swimsuit if you're headed somewhere sunny ☀️, and you leave the umbrella behind if it’s not the rainy season. In this exercise, we do the same — we only deploy certain Azure resources when the environment calls for them.

Let’s build it 💪


🧠 What We’re Learning

  • How to use conditions in Bicep (if (...))
  • When to deploy a storage account (for SQL auditing) only if the environment is Production
  • How to control auditing settings based on environment
  • Why conditional logic makes your infrastructure smarter and safer

🧱 Step 1: Base Template – SQL Server + Database

We started with a basic Bicep file called main.bicep that creates:

  • A SQL Server
  • A SQL Database (because our teddy bear product needs somewhere to keep HR data)

Here’s what our starting parameters and variables looked like:

@description('The Azure region into which the resources should be deployed.')
param location string

@secure()
@description('SQL Server Admin Login')
param sqlServerAdministratorLogin string

@secure()
@description('SQL Server Admin Password')
param sqlServerAdministratorLoginPassword string

@description('Database SKU (Performance Tier)')
param sqlDatabaseSku object = {
  name: 'Standard'
  tier: 'Standard'
}

var sqlServerName = 'teddy${location}${uniqueString(resourceGroup().id)}'
var sqlDatabaseName = 'TeddyBear'

Then we defined two resources:

resource sqlServer 'Microsoft.Sql/servers@2024-05-01-preview' = { ... }
resource sqlDatabase 'Microsoft.Sql/servers/databases@2024-05-01-preview' = { ... }

✅ So far, this will always deploy a database server — no matter the environment.


⚙️ Step 2: Add Conditional Parameters & Logic

We added:

@description('The name of the environment. This must be Development or Production.')
@allowed(['Development', 'Production'])
param environmentName string = 'Development'

@description('The name of the audit storage account SKU.')
param auditStorageAccountSkuName string = 'Standard_LRS'

Then created two key variables:

var auditingEnabled = environmentName == 'Production'
var auditStorageAccountName = take('bearaudit${location}${uniqueString(resourceGroup().id)}', 24)

🚦 What’s Happening Here?

  • auditingEnabled is a boolean — true if we’re deploying to Production.
  • take(...) ensures our storage account name doesn’t go over the 24-character limit (because naming rules are picky 🧠)

🧳 Step 3: Conditionally Add a Storage Account

We only want to collect auditing data if we’re in a production environment.

resource auditStorageAccount 'Microsoft.Storage/storageAccounts@2023-05-01' = if (auditingEnabled) {
  name: auditStorageAccountName
  location: location
  sku: {
    name: auditStorageAccountSkuName
  }
  kind: 'StorageV2'
}

That little if (auditingEnabled) is the magic. It’s like saying:

“Only pack this if we’re going on the important trip.”


🔍 Step 4: Add SQL Server Auditing

Now we wire the SQL Server to log data to that storage account — but only in Production.

resource sqlServerAudit 'Microsoft.Sql/servers/auditingSettings@2024-05-01-preview' = if (auditingEnabled) {
  parent: sqlServer
  name: 'default'
  properties: {
    state: 'Enabled'
    storageEndpoint: environmentName == 'Production' ? auditStorageAccount.properties.primaryEndpoints.blob : ''
    storageAccountAccessKey: environmentName == 'Production' ? auditStorageAccount.listKeys().keys[0].value : ''
  }
}

Here we used the ternary operator (aka the ?: symbol). Why?
Because even when a resource is conditionally deployed, Azure still checks every line. This avoids errors like:

“Hey, I don’t see that storage account you’re referencing” 🙃


🚀 Step 5: Deploy to Azure

We did the usual setup:

az bicep install && az bicep upgrade
az login
az group create --name BicepRG --location westus

Dev Deployment:

az deployment group create \
  --resource-group BicepRG \
  --name main \
  --template-file main.bicep \
  --parameters location=westus

We entered our SQL admin login + password when prompted.

💡 Since we didn’t set the environmentName, it defaulted to Development.

👉 That means the storage account and auditing didn’t get deployed — exactly what we wanted!


🔁 Step 6: Redeploy for Production

Now let’s simulate a Production rollout:

az deployment group create \
  --resource-group BicepRG \
  --name main \
  --template-file main.bicep \
  --parameters environmentName=Production location=westus

💥 Boom. This time:

  • We got the SQL Server
  • A Storage Account for auditing
  • Auditing enabled on the SQL Server

Just like switching a gear from “dry run” to “real world” 🧠


🔍 Step 7: Check the Results in Azure Portal

In the Azure Portal:

  1. Head to Resource Groups > BicepRG
  2. Select the SQL Server
  3. Go to Auditing
  4. You’ll see: ✅ State = Enabled ✅ Logging to the storage account

🧠 In Short

What We Did Why It Matters
Used if () conditions in Bicep Smarter templates → Less waste in dev, more protection in prod
Deployed SQL + DB to both envs Core infrastructure stays consistent
Only added auditing for prod Less cost and clutter in dev
Used ternary ? : logic Avoided reference errors in conditional deployments

🎒 Takeaway

This pattern — using conditions — is super useful when:

  • You're working with multiple environments
  • You want flexibility without duplicating code
  • You need governance (like logging or auditing) only in specific cases

Wanna follow my Azure learning journey?

Stick around — I’m sharing it all, wins and stumbles included 😄

You can find me on LinkedIn — drop me a message and just say hi 👋

Would love to hear what you're working on or learning!