Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
Azure Developer CLI (azd) supports layered provisioning, which you can use to define multiple provisioning layers in your azure.yaml file. Each layer points to its own set of Infrastructure as Code (IaC) templates. The CLI provisions layers one at a time, ordered by the dependencies between them. You can also provision or tear down individual layers independently.
This feature solves complex dependency scenarios where resources in one layer depend on resources from another layer. Instead of mixing IaC with imperative hook scripts, layered provisioning keeps everything declarative.
Note
Layered provisioning is currently a beta feature. Learn more about the versioning strategy.
When to use layered provisioning
Use layered provisioning when a single azd provision deployment can't handle all of your infrastructure needs in one step. Consider using layered provisioning when:
- Circular dependencies: Some resources need to reference other resources that must be created first, such as a virtual network that must exist before a private endpoint can be configured.
- Foundational infrastructure differs from application infrastructure: You manage shared networking, security, or identity resources separately from per-application resources.
- Independent lifecycle management is needed: You update and tear down different infrastructure components at different times. For example, a networking layer might be long-lived, while an application layer is frequently redeployed.
- Monorepo projects with distinct infrastructure groups: A single repository contains multiple independent services (such as an Event Hub, a Container App, and a Function App), each with its own infrastructure templates.
Configure layers in azure.yaml
Define layers under the infra section of your azure.yaml file. Each layer requires a name and a path pointing to the directory that contains the IaC templates for that layer.
name: my-app
infra:
layers:
- name: networking
path: ./infra/networking
- name: application
path: ./infra/application
services:
api:
project: ./src/api
language: js
host: containerapp
Important
Layer processing order: azd provision processes layers based on their dependencies. For Bicep layers and custom or extension providers, azd infers dependencies by scanning parameter files (*.bicepparam and *.parameters.json) for environment variable and layer output references, and it orders layers accordingly instead of strictly following the order listed in azure.yaml. Layers that have no inferred or declared dependencies run in the order they're listed. azd down follows the corresponding reverse order, so dependent layers are removed before the layers they depend on. Use the dependsOn property to declare ordering that azd can't infer.
Layer properties
Each layer supports the following properties:
| Property | Required | Description |
|---|---|---|
name |
Yes | A unique name for the layer. Use this name when targeting a specific layer with commands. |
path |
Yes | The relative path to the directory containing the IaC templates for this layer. |
module |
No | The name of the module within the layer's directory. Defaults to main. |
provider |
No | The IaC provider for this layer (bicep or terraform). Inherits from the root infra.provider if you don't specify it. |
dependsOn |
No | The names of other layers that this layer depends on. Use this property when ordering matters but azd can't infer the dependency from parameter references. |
Important
When you define infra.layers, you can't declare other properties on the infra section (path, module, deploymentStacks) at the root level. You must specify all infrastructure configuration within each layer.
Directory structure
A typical project using layered provisioning might have the following directory structure:
my-app/
├── azure.yaml
├── infra/
│ ├── networking/
│ │ └── main.bicep
│ └── application/
│ └── main.bicep
└── src/
└── api/
└── ...
Each layer directory contains its own complete set of IaC templates, just as a standard azd project's infra directory would.
Provision and manage layers
You can provision all layers at once or target a specific layer by name. The following sections describe common commands for provisioning, tearing down, and refreshing layer state.
Provision all layers
Run azd provision without arguments to provision all layers:
azd provision
azd processes each layer one at a time, ensuring that a layer completes before any layer that depends on it begins. For Bicep layers and custom or extension providers, azd infers dependencies from environment variable and layer output references in *.bicepparam and *.parameters.json files, so the execution order can differ from the order listed in azure.yaml. Layers with no inferred or declared dependencies run in the listed order. This process guarantees that dependent resources exist before layers that reference them are deployed.
Provision a specific layer
To provision only a specific layer, pass the layer name as an argument:
azd provision networking
This command deploys only the resources defined in the networking layer. Provisioning a specific layer is useful when:
- You're iterating on a single layer during development.
- You need to update one layer without redeploying others.
- You're setting up a new layer on top of existing infrastructure.
Tear down all layers
Run azd down without arguments to tear down resources from all layers. When multiple layers exist, azd processes them in the reverse of the provisioning order, so dependent resources are removed before the foundational resources they depend on:
azd down
Tear down a specific layer
To tear down only a specific layer, pass the layer name as an argument:
azd down application
This command removes only the resources deployed by the application layer, leaving the other layers intact.
Refresh environment state
You can refresh the environment state from a specific layer by using the --layer flag with azd env refresh:
azd env refresh --layer networking
This command updates the environment variables and outputs based on the most recent deployment of the specified layer.
Example: Monorepo with multiple services
The following example demonstrates layered provisioning for a monorepo that contains an Event Hub, a Container App running multiple containers, and an Azure Function App:
name: logging-app
infra:
layers:
- name: eventhub
path: ./infra/eventhub
- name: aca
path: ./infra/aca
- name: functionapp
path: ./infra/functionapp
services:
functionapp:
resourceName: ${site_name}
language: dotnet
project: ./src/function/functionapp.csproj
host: appservice
resourceGroup: ${rg_name}
The corresponding directory structure:
logging-app/
├── azure.yaml
├── infra/
│ ├── eventhub/
│ │ └── main.bicep
│ ├── aca/
│ │ └── main.bicep
│ └── functionapp/
│ └── main.bicep
└── src/
└── function/
└── functionapp.csproj
With this configuration, you can:
- Provision only the Event Hub infrastructure:
azd provision eventhub - Provision only the Container App infrastructure:
azd provision aca - Provision everything in order:
azd provision - Tear down only the Function App layer:
azd down functionapp
Example: Base and application layers
A common pattern separates shared or foundational infrastructure from per-application infrastructure:
name: my-app
infra:
layers:
- name: base
path: ./infra/base
- name: app
path: ./infra/app
services:
web:
project: ./src/web
language: js
host: containerapp
The base layer creates shared resources like networking, identity, and monitoring. The app layer creates the application-specific resources (such as a Container App environment and container apps) that reference the base resources.
During development, you might provision the base layer once and iterate on the application layer:
azd provision base
azd provision app
azd provision app # re-provision only the app layer after changes
Example: Mixed IaC providers
Each layer can use a different IaC provider. For example, you might use Bicep for networking and Terraform for the application layer:
name: my-app
infra:
layers:
- name: networking
path: ./infra/networking
provider: bicep
- name: application
path: ./infra/application
provider: terraform
The built-in non-Bicep providers (Terraform, Pulumi, ARM, and the test provider) are opaque to dependency inference, because azd can't analyze their inputs for references to other layers. Use an explicit dependsOn property whenever ordering between those layers, or between those layers and other layers, matters:
name: my-app
infra:
layers:
- name: networking
path: ./infra/networking
provider: bicep
- name: application
path: ./infra/application
provider: terraform
dependsOn:
- networking
Considerations and limitations
- When you provision all layers,
azdprocesses them one at a time based on their dependencies. For Bicep layers and custom or extension providers,azdinfers dependencies from environment variable and layer output references in*.bicepparamand*.parameters.jsonfiles. Layers without inferred or declared dependencies run in the order you define. - The built-in non-Bicep providers (Terraform, Pulumi, ARM, and the test provider) are opaque for dependency inference. Use an explicit
dependsOnproperty when ordering involving those layers matters. - Explicit
dependsOnis also required when ordering matters butazdcan't infer the dependency from parameter references. For example, usedependsOnwhen one layer'spostprovisionhook produces a value that another layer consumes, because hook-produced values don't appear as output references in*.bicepparamor*.parameters.jsonfiles. - When you tear down all layers,
azdprocesses them in the reverse of the provisioning order.- If multiple layers deploy resources into the same Azure resource group and you use the default resource-group–based deletion behavior, shared resources may be deleted when running azd down.
- To allow independent tracking and deletion of layered infrastructure, enable deployment stacks by running the command
azd config set alpha.deployment.stacks on.
- You can't use the
--previewflag when provisioning multiple layers at once. Specify a<layer>name to use preview mode. - Layers operate independently in terms of IaC. To reference outputs from one layer in another layer, use environment variables that
azdsets after each layer's deployment. Referencing those environment variables from a*.bicepparamor*.parameters.jsonfile also letsazdinfer the ordering between the layers. - All standard
azdprovisioning features (deployment state caching, hooks, parameters, Bicep, or Terraform) work within each individual layer.- Command-level hooks (for example,
preprovision,postprovision) are invoked once per layer. When multiple layers are defined, hooks run for each layer in the order layers are processed.
- Command-level hooks (for example,