```
az deployment group create --resource-group [rg] --template-file main.bicep --parameters env=prod --name deploy-[env]-$(date +%Y%m%d)
```
Traps:
- **Always what-if first.** `az deployment group what-if --resource-group [rg] --template-file main.bicep` shows create/modify/delete per resource. A "delete" line on a resource you did not intend to remove is the signal to stop. what-if is not perfect (it cannot see data-plane state), but it catches the disasters.
- **Deployment mode.** Default is Incremental: resources not in the template are left alone. Complete mode deletes them. Complete mode on the wrong resource group deletes the resource group contents. Never use Complete unless you mean it, and never in a script without what-if.
- **Deployment names.** Reusing the same deployment name is fine (it becomes a new deployment entry); the 409 "conflict" people hit is usually a resource-level conflict (name taken), not the deployment name.
- **Outputs for wiring.** `output storageAccountName string = sa.name` then read with `az deployment group show`. Do not hardcode resource names in two places.
- **Modules.** Split into modules (network.bicep, storage.bicep) with explicit params. A 2000-line main.bicep is where the what-if surprises hide.
- **Bicep version.** `az bicep version` and `az bicep upgrade`. Old Bicep versions fail to compile newer syntax with cryptic errors; upgrade before debugging the template.
Verify: what-if output matches intent, deployment state Succeeded in `az deployment group show`, then smoke-test the resource (endpoint responds, role assignment exists).