Exploring the Bicep @onlyIfNotExists decorator
The Bicep @onlyIfNotExists decorator lets you create resources once without overwriting them on subsequent deployments. Perfect for Key Vault secrets and other "create but don't touch" scenarios.
With the recent release of Bicep v0.38.3 (read the release notes here: https://github.com/Azure/bicep/releases/tag/v0.38.3), the Bicep team have moved an exciting new feature to GA: The @onlyIfNotExists decorator 🎉
In this story, we’ll check out what it is, how it works, and why it’s exciting. Let’s go 🚴
What does it do?
Because Bicep describes the desired state of Azure infrastructure, it was really hard to handle infrastructure which you may want to initially deploy, but not overwrite changes to it which would happen outside of Bicep before.
One example for this are Key Vault secrets. I’d often run into the case, where I’d want to create secrets during the Bicep deployment in order to be able to reference them in other pieces of infrastructure. However, I did not want their values to be overwritten by subsequent deployments. They should be created once, but then not be touched again.
This is the exact problem, the @onlyIfNotExists resource decorator is solving. When using it, the resource gets created once, but not be touched again by subsequent Bicep deployments, as long as the resource still exists. This allows for deployments to be idempotent without needing to build some complex logic around it.
The decorator in action
I’ve prepared a small Bicep deployment with one Key Vault and two secrets for a quick showcase. One secret is created with the @onlyIfNotExists decorator (secret A), one without (secret B). Here is the deployment:
resource resKeyVault 'Microsoft.KeyVault/vaults@2025-05-01' = {
name: 'kv-onlyIfNotExists'
location: 'germanywestcentral'
properties: {
sku: {
name: 'standard'
family: 'A'
}
tenantId: tenant().tenantId
enableRbacAuthorization: true
accessPolicies: []
}
}
@onlyIfNotExists()
resource resSecretA 'Microsoft.KeyVault/vaults/secrets@2025-05-01' = {
name: 'secretA-onlyIfNotExists'
parent: resKeyVault
properties: {
value: 'mySecretValueA'
}
}
resource resSecretB 'Microsoft.KeyVault/vaults/secrets@2025-05-01' = {
name: 'secretB-deployAlways'
parent: resKeyVault
properties: {
value: 'mySecretValueB'
}
}Checking the values, we can see that both secrets are indeed configured as defined in the Bicep deployment:

Now, let’s update both to new values:

Finally, let’s check the values again after re-deploying the bicep template above:

We can see, that the value for secret A persisted, while the value for secret B got reset to the value defined in the Bicep deployment.
Bye
I hope you found this interesting and maybe even useful. The new decorator is a very welcome addition to Bicep for me and something I will 100% use often. One thing I would like to see, is that the decorator also works for modules. I could definitely see some challenges with this, so I doubt it would ever be added.
I’d love to hear your thoughts and any other feedback! Feel free to leave them in the comments. ❤️
If you like what you’ve read, I’d really appreciate it if you share this article 🔥
Until next time! 👋