Bicep Resources

The resource declaration is the core of every Bicep file. It tells Azure what to create, where to create it, and how to configure it. Everything covered so far — parameters, variables, and file structure — exists to support well-written resource declarations.

A resource in Bicep represents one Azure service: a storage account, virtual machine, web app, database, virtual network, or any of the hundreds of services available in Azure. Each resource gets its own declaration block in the Bicep file.

Resource Declaration Syntax

resource <symbolicName> '<ResourceType>@<ApiVersion>' = {
  name: '<resourceName>'
  location: '<region>'
  <additional properties>
}

Breaking this down into its four parts:

resource storageAccount 'Microsoft.Storage/storageAccounts@2023-01-01' = {
   │           │                    │                       │
   │           │                    │                       └── API Version
   │           │                    └────────────────────────── Resource Type
   │           └─────────────────────────────────────────────── Symbolic Name
   └─────────────────────────────────────────────────────────── Keyword
PartPurposeRules
Symbolic NameRefers to this resource elsewhere in the fileUnique within the file, camelCase recommended
Resource TypeIdentifies which Azure service to createFormat: Provider/Type (case-sensitive)
API VersionSpecifies which version of the Azure API to useDate format YYYY-MM-DD, use latest stable
Properties BlockConfigures the resource settingsEach resource type has different required/optional properties

Common Azure Resource Types

Azure ServiceResource Type
Storage AccountMicrosoft.Storage/storageAccounts
Virtual MachineMicrosoft.Compute/virtualMachines
App Service PlanMicrosoft.Web/serverfarms
Web AppMicrosoft.Web/sites
SQL ServerMicrosoft.Sql/servers
SQL DatabaseMicrosoft.Sql/servers/databases
Virtual NetworkMicrosoft.Network/virtualNetworks
Key VaultMicrosoft.KeyVault/vaults
Container RegistryMicrosoft.ContainerRegistry/registries
Cosmos DB AccountMicrosoft.DocumentDB/databaseAccounts

Resource Properties

Every resource type has a set of required and optional properties. Required properties must always be present. Optional properties use Azure defaults when omitted.

Required Properties for Almost Every Resource

  • name – The name of the resource in Azure. Must follow Azure naming rules for each service.
  • location – The Azure region where the resource is created (e.g., 'eastus', 'westeurope').

Common Optional Properties

  • tags – Key-value pairs for organizing and billing resources.
  • sku – The pricing tier or performance level (e.g., 'Standard_LRS', 'B1').
  • kind – A sub-type of the resource (e.g., 'StorageV2', 'FunctionApp').
  • properties – Service-specific configuration settings.
  • identity – Managed identity settings.

Example 1 – Storage Account

param location string = 'eastus'
param storageAccountName string = 'mystorage2024abc'

resource storageAccount 'Microsoft.Storage/storageAccounts@2023-01-01' = {
  name: storageAccountName
  location: location
  tags: {
    environment: 'production'
  }
  sku: {
    name: 'Standard_LRS'
  }
  kind: 'StorageV2'
  properties: {
    minimumTlsVersion: 'TLS1_2'
    allowBlobPublicAccess: false
    supportsHttpsTrafficOnly: true
  }
}

Example 2 – App Service Plan and Web App (Two Resources)

param location string = 'eastus'

resource appServicePlan 'Microsoft.Web/serverfarms@2023-01-01' = {
  name: 'asp-myapp'
  location: location
  sku: {
    name: 'B1'
    tier: 'Basic'
  }
}

resource webApp 'Microsoft.Web/sites@2023-01-01' = {
  name: 'app-myapp-prod'
  location: location
  kind: 'app'
  properties: {
    serverFarmId: appServicePlan.id
  }
}

Notice that webApp references appServicePlan.id — the symbolic name followed by .id. This is how resources reference each other in Bicep without hardcoding IDs.

Resource Dependencies

Azure must create some resources before others. For example, a Web App cannot exist without an App Service Plan. Bicep detects dependencies automatically when one resource references another resource's property.

Automatic Dependency Detection

appServicePlan ──────────────────────────────────┐
  (created first)                                │
                                                 ▼
webApp uses: serverFarmId: appServicePlan.id   webApp
  (created after appServicePlan)               (created second)

When Bicep sees appServicePlan.id inside the web app block, it knows to create the App Service Plan first. This implicit dependency is the recommended approach.

Explicit Dependencies with dependsOn

In rare cases where a resource needs to wait for another resource but does not directly reference it, use the dependsOn property.

resource scriptRunner 'Microsoft.Resources/deploymentScripts@2023-08-01' = {
  name: 'run-setup-script'
  location: location
  kind: 'AzureCLI'
  dependsOn: [
    storageAccount    // wait for storage account before running script
  ]
  properties: {
    azCliVersion: '2.50.0'
    scriptContent: 'echo "Setup complete"'
    retentionInterval: 'PT1H'
  }
}

Parent-Child Resources

Some Azure resources only exist inside another resource. A SQL Database lives inside a SQL Server. A Blob Container lives inside a Storage Account. These are called parent-child resource relationships.

Azure Resource Hierarchy Example

SQL Server (Parent)
│
├── SQL Database 1 (Child)
├── SQL Database 2 (Child)
└── SQL Database 3 (Child)

Method 1 – Using the parent Property (Recommended)

resource sqlServer 'Microsoft.Sql/servers@2023-08-01-preview' = {
  name: 'sql-myapp'
  location: location
  properties: {
    administratorLogin: 'sqladmin'
    administratorLoginPassword: adminPassword
  }
}

resource sqlDatabase 'Microsoft.Sql/servers/databases@2023-08-01-preview' = {
  name: 'db-orders'
  parent: sqlServer     // links this database to the SQL server above
  location: location
  sku: {
    name: 'Basic'
    tier: 'Basic'
  }
}

Method 2 – Nested Resource (Alternative)

resource sqlServer 'Microsoft.Sql/servers@2023-08-01-preview' = {
  name: 'sql-myapp'
  location: location
  properties: {
    administratorLogin: 'sqladmin'
    administratorLoginPassword: adminPassword
  }

  // Database is nested directly inside the server block
  resource sqlDatabase 'databases' = {
    name: 'db-orders'
    location: location
    sku: {
      name: 'Basic'
    }
  }
}

Managed Identity on Resources

Many Azure resources support Managed Identity — a way to authenticate to other Azure services without storing secrets. Assign a managed identity directly in the resource block:

resource webApp 'Microsoft.Web/sites@2023-01-01' = {
  name: 'app-myapp-prod'
  location: location
  kind: 'app'
  identity: {
    type: 'SystemAssigned'   // Azure creates and manages the identity
  }
  properties: {
    serverFarmId: appServicePlan.id
  }
}

Referencing Resource Properties

After declaring a resource, its properties become accessible throughout the file using the symbolic name followed by a dot and the property name.

// Access resource properties using the symbolic name
storageAccount.id                           // Resource ID
storageAccount.name                         // Resource name
storageAccount.location                     // Location
storageAccount.properties.primaryEndpoints.blob   // Blob endpoint URL
webApp.identity.principalId                 // Managed identity principal ID

Complete Example – Three Connected Resources

param location string = 'eastus'
param environment string = 'prod'

var prefix = 'myapp-${environment}'

resource storageAccount 'Microsoft.Storage/storageAccounts@2023-01-01' = {
  name: 'st${replace(prefix, '-', '')}001'
  location: location
  sku: {
    name: 'Standard_LRS'
  }
  kind: 'StorageV2'
  properties: {
    supportsHttpsTrafficOnly: true
  }
}

resource appServicePlan 'Microsoft.Web/serverfarms@2023-01-01' = {
  name: 'asp-${prefix}'
  location: location
  sku: {
    name: 'B1'
    tier: 'Basic'
  }
}

resource webApp 'Microsoft.Web/sites@2023-01-01' = {
  name: 'app-${prefix}'
  location: location
  kind: 'app'
  identity: {
    type: 'SystemAssigned'
  }
  properties: {
    serverFarmId: appServicePlan.id   // implicit dependency
    siteConfig: {
      appSettings: [
        {
          name: 'STORAGE_ACCOUNT_NAME'
          value: storageAccount.name
        }
      ]
    }
  }
}

Summary

Resource declarations are the heart of Bicep. Every resource uses a symbolic name, a type string, an API version, and a properties block. Bicep detects dependencies automatically when resources reference each other. Parent-child relationships use the parent property or nested resource blocks. Resources expose their properties through their symbolic name, making it easy to connect related resources cleanly.

Leave a Comment