Bicep Existing Resources
Not every Azure resource needs creation from scratch. Many real-world Bicep templates work alongside resources that already exist — a shared Key Vault managed by a security team, a virtual network set up by the networking team, or a Log Analytics workspace used by multiple applications. The existing keyword lets Bicep reference these pre-existing resources and use their properties without creating or modifying them.
Think of it like moving into a furnished apartment. The walls, plumbing, and furniture are already there. A move-in checklist references those existing items and assigns them new uses — the desk becomes a workspace, the shelves hold books — without rebuilding the apartment from scratch. Bicep's existing keyword does the same: it references what is already there and uses it in new deployments.
The existing Keyword – Syntax
resource <symbolicName> '<ResourceType>@<ApiVersion>' existing = {
name: '<existingResourceName>'
}
The only difference from a normal resource declaration is the word existing before the opening brace. No properties block is needed — Bicep reads the resource from Azure rather than creating it. The symbolic name then provides access to that resource's properties throughout the rest of the file.
Simple Example – Reference an Existing Key Vault
param keyVaultName string = 'kv-shared-security'
param location string = 'eastus'
// Reference an existing Key Vault managed by the security team
resource keyVault 'Microsoft.KeyVault/vaults@2023-07-01' existing = {
name: keyVaultName
}
// Create a new Web App that reads secrets from the existing Key Vault
resource webApp 'Microsoft.Web/sites@2023-01-01' = {
name: 'app-mywebapp'
location: location
kind: 'app'
properties: {
serverFarmId: appServicePlan.id
siteConfig: {
appSettings: [
{
name: 'KEY_VAULT_URI'
value: keyVault.properties.vaultUri // ← read from existing resource
}
]
}
}
}
The Key Vault is not modified in any way. Bicep simply reads its vaultUri property and passes it to the new Web App as an environment variable.
What Properties Are Available on Existing Resources
All properties of the existing resource become available through the symbolic name — the same properties available when Bicep creates the resource itself.
// Existing storage account
resource storageAccount 'Microsoft.Storage/storageAccounts@2023-01-01' existing = {
name: 'myexistingstorage001'
}
// Access its properties
var blobEndpoint = storageAccount.properties.primaryEndpoints.blob
var storageId = storageAccount.id
var storageName = storageAccount.name
var storageRgScope = storageAccount.id
Referencing an Existing Resource in a Different Resource Group
By default, Bicep looks for the existing resource in the same resource group as the deployment. To reference a resource in a different resource group, add the scope property.
Deployment Resource Group: rg-myapp Existing Resource Group: rg-shared-infra ┌──────────────────────┐ ┌──────────────────────────┐ │ rg-myapp │ │ rg-shared-infra │ │ │ │ │ │ new webApp ───────┼────────┼──► existing keyVault │ │ │ scope │ │ └──────────────────────┘ └──────────────────────────┘
param sharedResourceGroup string = 'rg-shared-infra'
param keyVaultName string = 'kv-shared-prod'
param location string = 'eastus'
// Reference a Key Vault in a DIFFERENT resource group
resource keyVault 'Microsoft.KeyVault/vaults@2023-07-01' existing = {
name: keyVaultName
scope: resourceGroup(sharedResourceGroup) // ← point to the other resource group
}
// Use the Key Vault URI in a new resource in the current resource group
resource webApp 'Microsoft.Web/sites@2023-01-01' = {
name: 'app-mywebapp'
location: location
kind: 'app'
properties: {
serverFarmId: appServicePlan.id
siteConfig: {
appSettings: [
{
name: 'KEY_VAULT_URI'
value: keyVault.properties.vaultUri
}
]
}
}
}
Referencing an Existing Resource in a Different Subscription
param sharedSubscriptionId string = 'aaaa-bbbb-cccc-dddd'
param sharedResourceGroup string = 'rg-central-infra'
param logWorkspaceName string = 'log-central-analytics'
// Reference a Log Analytics workspace in a different subscription
resource logWorkspace 'Microsoft.OperationalInsights/workspaces@2023-09-01' existing = {
name: logWorkspaceName
scope: resourceGroup(sharedSubscriptionId, sharedResourceGroup)
}
// Use its resource ID when setting up diagnostics
resource diagnosticSetting 'Microsoft.Insights/diagnosticSettings@2021-05-01-preview' = {
name: 'send-to-central-log'
scope: storageAccount
properties: {
workspaceId: logWorkspace.id // ← cross-subscription workspace ID
logs: []
metrics: [
{
category: 'Transaction'
enabled: true
}
]
}
}
Existing Child Resources
Referencing a child resource (like a subnet inside a VNet, or a secret inside a Key Vault) requires referencing the parent first, then the child.
Method 1 – Reference Parent Then Use Child Name
param vnetName string = 'vnet-shared-prod'
param subnetName string = 'app-subnet'
// Reference the existing parent virtual network
resource vnet 'Microsoft.Network/virtualNetworks@2023-09-01' existing = {
name: vnetName
}
// Reference the specific subnet inside the existing VNet
resource subnet 'Microsoft.Network/virtualNetworks/subnets@2023-09-01' existing = {
name: subnetName
parent: vnet // ← use parent property to link to existing parent
}
// Use the subnet ID in a new network interface
resource networkInterface 'Microsoft.Network/networkInterfaces@2023-09-01' = {
name: 'nic-myvm-001'
location: 'eastus'
properties: {
ipConfigurations: [
{
name: 'ipconfig1'
properties: {
subnet: {
id: subnet.id // ← subnet ID from existing resource
}
privateIPAllocationMethod: 'Dynamic'
}
}
]
}
}
Method 2 – Nested existing Reference
resource vnet 'Microsoft.Network/virtualNetworks@2023-09-01' existing = {
name: 'vnet-shared-prod'
resource subnet 'subnets' existing = {
name: 'app-subnet'
}
}
// Access using parent::child notation
var subnetId = vnet::subnet.id
Assigning RBAC Roles to Existing Resources
One of the most common uses of existing resources is assigning Role-Based Access Control (RBAC) roles. The new resource (like a Managed Identity on a Web App) needs access to an existing resource (like a Storage Account or Key Vault).
param location string = 'eastus'
param existingStorageName string = 'sharedstorageaccount'
// Reference the existing storage account
resource existingStorage 'Microsoft.Storage/storageAccounts@2023-01-01' existing = {
name: existingStorageName
}
// Create a new Web App with Managed Identity
resource webApp 'Microsoft.Web/sites@2023-01-01' = {
name: 'app-mywebapp'
location: location
kind: 'app'
identity: {
type: 'SystemAssigned'
}
properties: {
serverFarmId: appServicePlan.id
}
}
// Assign the Storage Blob Data Reader role to the Web App
// so it can read blobs from the existing storage account
var storageBlobDataReaderRoleId = '2a2b9908-6ea1-4ae2-8e65-a410df84e7d1'
resource roleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
name: guid(existingStorage.id, webApp.id, storageBlobDataReaderRoleId)
scope: existingStorage // ← assign the role ON the existing resource
properties: {
roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', storageBlobDataReaderRoleId)
principalId: webApp.identity.principalId
principalType: 'ServicePrincipal'
}
}
When existing Is Not the Right Tool
| Scenario | Use existing? | Better Approach |
|---|---|---|
| Resource created elsewhere and used here | Yes | existing keyword |
| Resource created by this Bicep file | No | Use symbolic name directly |
| Resource may or may not exist yet | No | Pass resource ID as a parameter |
| Modifying an existing resource's settings | No | Declare it as a normal resource (Bicep manages idempotency) |
Passing Resource IDs as Parameters – An Alternative Pattern
When the existing resource lives in a completely separate subscription and the cross-subscription scope syntax is too complex, passing the resource ID as a parameter is a simpler alternative.
// Alternative: pass the existing resource ID as a parameter
param existingSubnetId string // Full resource ID passed in at deploy time
param location string = 'eastus'
resource networkInterface 'Microsoft.Network/networkInterfaces@2023-09-01' = {
name: 'nic-myvm-001'
location: location
properties: {
ipConfigurations: [
{
name: 'ipconfig1'
properties: {
subnet: {
id: existingSubnetId // ← ID passed in as a parameter
}
privateIPAllocationMethod: 'Dynamic'
}
}
]
}
}
Deploy with the subnet ID provided on the command line:
az deployment group create \ --resource-group myRG \ --template-file main.bicep \ --parameters existingSubnetId='/subscriptions/aaaa/resourceGroups/rg-network/providers/Microsoft.Network/virtualNetworks/vnet-prod/subnets/app-subnet'
Complete Example – New App Using Four Existing Resources
param location string = 'eastus'
param environment string = 'prod'
param sharedRG string = 'rg-shared-infra'
// Reference four existing shared resources
resource keyVault 'Microsoft.KeyVault/vaults@2023-07-01' existing = {
name: 'kv-shared-${environment}'
scope: resourceGroup(sharedRG)
}
resource logWorkspace 'Microsoft.OperationalInsights/workspaces@2023-09-01' existing = {
name: 'log-shared-${environment}'
scope: resourceGroup(sharedRG)
}
resource vnet 'Microsoft.Network/virtualNetworks@2023-09-01' existing = {
name: 'vnet-shared-${environment}'
scope: resourceGroup(sharedRG)
}
resource appSubnet 'Microsoft.Network/virtualNetworks/subnets@2023-09-01' existing = {
name: 'app-subnet'
parent: vnet
}
// Create App Service Plan
resource appServicePlan 'Microsoft.Web/serverfarms@2023-01-01' = {
name: 'asp-myapp-${environment}'
location: location
sku: {
name: 'B1'
}
}
// Create Web App that uses all four existing resources
resource webApp 'Microsoft.Web/sites@2023-01-01' = {
name: 'app-myapp-${environment}'
location: location
kind: 'app'
identity: {
type: 'SystemAssigned'
}
properties: {
serverFarmId: appServicePlan.id
virtualNetworkSubnetId: appSubnet.id // join existing subnet
siteConfig: {
appSettings: [
{
name: 'KEY_VAULT_URI'
value: keyVault.properties.vaultUri // use existing KV URI
}
{
name: 'LOG_WORKSPACE_ID'
value: logWorkspace.properties.customerId // use existing workspace
}
]
}
}
}
output webAppUrl string = 'https://${webApp.properties.defaultHostName}'
Summary
The existing keyword lets Bicep reference Azure resources that already exist without creating or modifying them. Existing resources expose all their properties through the symbolic name, just like freshly created resources. Cross-resource-group references use the scope property with resourceGroup(). Child resources reference their parent using the parent property. Common use cases include reading Key Vault URIs, obtaining subnet IDs for new VMs, and assigning RBAC roles to managed identities on existing resources.
