I've been thinking recently about what a deployment actually is. When you deploy a resource via the portal, ARM, or Bicep, you'll notice under the deployment scope that there's something called a deployment. This is also apparent when using Bicep modules and CLI deployments.
For example, nesting Bicep modules like this—with a main.bicep file calling modules that call other modules.
When deployed using the az deployment CLI command:
# log into azure
az login
# create a resource group
az group create -n rg -l uksouth
# create deployment
az deployment group create -n my-deployment -g rg -f main.bicep
What is ARM
First, let's talk about what Azure Resource Manager (ARM) is. It's the management layer that takes requests for provisioning resources and actions them. When we use the portal, CLI, ARM templates, or Bicep, we're ultimately interacting with ARM. It acts as the management layer, checking the validity of requests and ensuring sufficient permissions (using its own permissions system). All requests for control plane activities and updates are sent to ARM at https://management.azure.com.
The diagram demonstrates this nicely—no matter how the request for resources is made, it's ARM that acts as the management layer for requests, the gateway to the resource providers.
Resource providers are another important component of provisioning Azure services. They're the way ARM distributes requests to the relevant APIs that know how to provision the required resources. For example, a request for a virtual machine like this:
resource vm 'Microsoft.Compute/virtualMachines@2024-03-01' = {
name: 'myExampleVM'
location: 'uksouth'
properties: {
hardwareProfile: {
vmSize: 'Standard_B2s'
}
osProfile: {
computerName: 'myvm'
adminUsername: 'azureuser'
adminPassword: 'P@ssw0rd123!'
}
storageProfile: {
imageReference: {
publisher: 'Canonical'
offer: 'Ubuntu2204'
sku: '22_04-lts-gen2'
version: 'latest'
}
osDisk: {
createOption: 'FromImage'
managedDisk: {
storageAccountType: 'Standard_LRS'
}
}
}
networkProfile: {
networkInterfaces: [
{
id: networkInterface.id // Reference to a NIC resource (not shown for brevity)
}
]
}
}
}
Sent to the Microsoft.KeyVault namespace will fail because Microsoft.KeyVault doesn't know what to do with properties.osProfile.computerName or any Microsoft.Compute properties—as this isn't a Key Vault property (or in the Key vault schema). Only Microsoft.Compute/ knows how to handle it.
Pretty much every resource has a resource provider, which is accessed via ARM.
Microsoft.Compute/virtualMachines
Microsoft.ContainerInstance
Microsoft.ContainerRegistry
Microsoft.AzureStack
These resource providers know how to handle requests for provisioning the resources they control. The resource providers define the operations for managing the resource and its configuration.
They also represent the AUTH layer. You might notice that any resource provider URL looks like an API—that's because it is an API. It has permissions to perform activities or verbs like write, read, and delete. An object in a tenant's directory can have the authorization to perform actions on resource providers.
Microsoft.ResourceProvider/resource/action
This is how authorisation to perform actions on Azure resources—including creating them—works.
Subscriptions need resource providers registered to them, so we can conclude resource providers live in subscriptions. Not enabling resource providers by default is a good security practice.
So ARM takes requests for resources, and resource providers are APIs used to control and manage types of resources. Authorisation is accomplished using permissions over exposed RP APIs. But what is a deployment?
Even the Resource Manager documentation doesn't explicitly call out what a deployment is.
- resource - A manageable item that's available through Azure.
- resource group - A container that holds related resources for an Azure solution.
- resource provider - A service that supplies Azure resources.
- declarative syntax - Syntax that lets you state, "Here's what I intend to create,"
- ARM template - A JavaScript Object Notation (JSON) file that defines one or more resources to deploy to a resource group, subscription, management group, or tenant.
- Bicep file - A file for declaratively deploying Azure resources.
- extension resource - A resource that adds to another resource's capabilities.
So a resource is a manageable item, a resource group is a logical container for resources and a resource provider is a service that supplies resources - but still no mention of a deployment.
If we check a subscription's resource providers, we can see a resource provider called Microsoft.Resources, which is "registration free." This means its status—whether registered or unregistered—doesn't matter. You also can't unregister it.
More clues can be found in the output of our deployment above.
{
"id": "/subscriptions/x/resourceGroups/rg/providers/Microsoft.Resources/deployments/my-deployment",
"location": null,
"name": "my-deployment",
"properties": {
"correlationId": "51e7f54e-9367-49bb-8a6e-613c00de3884",
"debugSetting": null,
"dependencies": [],
"duration": "PT7.8943772S",
"error": null,
"mode": "Incremental",
"onErrorDeployment": null,
"outputResources": [],
"outputs": {
"greeting": {
"type": "String",
"value": "Help Im stuck!"
}
},
"parameters": null,
"parametersLink": null,
"providers": [
{
"id": null,
"namespace": "Microsoft.Resources",
"providerAuthorizationConsentState": null,
"registrationPolicy": null,
"registrationState": null,
"resourceTypes": [
{
"aliases": null,
"apiProfiles": null,
"apiVersions": null,
"capabilities": null,
"defaultApiVersion": null,
"locationMappings": null,
"locations": [
null
],
"properties": null,
"resourceType": "deployments",
"zoneMappings": null
}
]
}
],
"provisioningState": "Succeeded",
"templateHash": "439532930182033670",
"templateLink": null,
"timestamp": "2025-11-23T11:49:51.148630+00:00",
"validatedResources": null
},
"resourceGroup": "rg",
"tags": null,
"type": "Microsoft.Resources/deployments"
}
We can see for the fields ‘type’ and ‘id’ the provider is ‘providers/Microsoft.Resources’ and ‘Microsoft.Resources/deployments’ we can also see in the API reference documentation that a deployment is a resource
Okay so what happens when we use this Microsoft.Resources resources to deploy our main.bicep? So the first step is to convert our bicep main.bicep into json
build our arm template
az bicep build --file main.bicep
Next step we create a new file deployment.bicep using the Microsoft.Resources/deployments resource type
resource nested 'Microsoft.Resources/deployments@2021-04-01' = {
name: 'nestedDeployment'
properties: {
mode: 'Incremental'
template: loadJsonContent('main.json')
}
}
and we can now deploy this again using az cli
az deployment group create -n my-deployment -g rg -f deployment.bicep --debug
he result is we have another deployment in the portal, but this one contains all our previously nested deployments nestedDeployment, my-deployment then level 1 - level 4. So using Bicep we created a deployment to deploy our deployment which contains 4 other nested deployments. It seems that deployments are how we package requests to ARM for the provisioning of resources and this is automatically done for us by az cli.
Validation and safety nets
So now we know, a deployment is created as a resource itself—specifically a Microsoft.Resources/deployments resource—whose sole job is to orchestrate the creation of other resources defined in its template property. It is the 'container' for the instructions we send to ARM, and because it is a resource, it can be nested inside other deployments just like any other Azure resource.
We can provision resources which aren't wrapped in a deployment by using rest calls for example using the az rest command
➜ what-is-a-deployment az rest --method put \
--url "https://management.azure.com/subscriptions/xxxx/resourceGroups/rg/providers/Microsoft.Storage/storageAccounts/sa4d56frv67tbyiun?api-version=2023-01-01" \
--body '{
"location": "uksouth",
"sku": {
"name": "Standard_LRS"
},
"kind": "StorageV2",
"properties": {
"minimumTlsVersion": "TLS1_2"
}
}'
We can by pass the deployment resource and ask the Microsoft.Storage/storageAccounts resource provider to provision a storage account for us, no need to get the deployments resource involved, and we can check this in the portal too.
Summary
An Azure deployment is a special type of resource which acts as a wrapper for requests to ARM. it provides deployment validation, auditability and monitors the progress of a deployment. We can’t know a if our template will fail or succeed until we ask the resource provider.





Top comments (0)