Modules & Parameters
Structure larger Bicep deployments with modules, parameter files, and decorators.
As deployments grow, split them into modules — separate .bicep files called
from a main template. A module encapsulates a piece of infrastructure (a network, a
database) with its own params and outputs, and you wire modules together by passing
one’s outputs into another.
Parameter files (.bicepparam or JSON) supply environment-specific values, so
the same template deploys dev and prod. Decorators add validation:
@minLength, @allowed, @secure (for passwords). This keeps templates reusable,
validated, and DRY.
// main.bicep
@allowed(['dev', 'prod'])
param env string
module network './modules/network.bicep' = {
name: 'network'
params: { env: env }
}
module app './modules/app.bicep' = {
name: 'app'
params: { subnetId: network.outputs.subnetId }
}az deployment group create -g rg -f main.bicep -p main.bicepparam - Split a template into a network module and an app module that consumes its output.
- Add an
@alloweddecorator restricting an environment parameter. - Mark a password parameter
@secureand explain why. - Describe how a parameter file enables dev vs prod from one template.
Cheat Sheet▾
| Feature | Syntax |
|---|---|
| Module call | module x './x.bicep' = { params: {…} } |
| Module output | x.outputs.value |
| Param file | .bicepparam / JSON |
| Allowed values | @allowed([…]) |
| Length validation | @minLength / @maxLength |
| Secret param | @secure() |
Common Interview Questions▾
How do Bicep modules pass data between each other?
A module exposes outputs; you reference them (e.g. network.outputs.subnetId) and pass them as params into another module, which also wires up deployment order.
What does the @secure() decorator do?
It marks a parameter (like a password) as sensitive so its value is excluded from deployment logs and output history.