When you start building Azure resources with Bicep, you’ll quickly run into these strange little @
symbols floating above your parameters:
|
|
They look harmless enough, but what’s actually happening here?
What Are Bicep Decorators?
Bicep decorators — one of the most underrated features in Infrastructure-as-Code, are like annotations — bits of metadata or behavior you can attach to parameters, variables, resources, and outputs.
They don’t change what gets deployed. They change how it’s validated, displayed, or controlled during deployment.
If you’ve ever used attributes in C# or decorators in Python/TypeScript, the concept will feel familiar.
Why Decorators Matter
Most Bicep templates start life simple — a few parameters, a couple of resources, and some outputs. Then, as environments scale, those templates become shared, reused, and parameterized by multiple teams.
That’s where decorators shine:
- âś… They make templates self-documenting
- đź§ They add input validation
- đź§± They integrate with portal UI metadata
- 🕵️ They make your code easier to read and maintain
In other words: they turn your IaC from “it works” to “it scales.”
Common Decorators
Here’s a quick cheat sheet of the decorators you’ll actually use day to day:
Decorator | Description | Example |
---|---|---|
@allowed([...]) | Restricts parameter values to a set of options. | @allowed(['dev','test','prod']) |
@batch(1) | Control loop concurrency during deployment. | @batch(1) |
@description('…') | Adds inline documentation for tooling and readers. | @description('Admin username for the VM.') |
@discriminator('…') | Used for tagged union types (advanced). | — |
@export() | Expose elements for import in other files. | — |
@metadata({…}) | Attach structured data used by tooling or AVM. | @metadata({ category: 'network' }) |
@minLength(n) / @maxLength(n) | Enforces input length limits. | @minLength(3) |
@minValue(n) / @maxValue(n) | Numeric limits for integer parameters. | @maxValue(5) |
@sealed() | Prevents typos in object properties. | @sealed() param tags object |
@secure() | Hides secrets from deployment logs. | @secure() param password string |
Example: Clean, Validated Parameters
Here’s what a production-ready parameter block should look like:
|
|
Result: Anyone using this module instantly knows what each value is, what’s valid, and what’s sensitive — no extra documentation needed.
The Hidden Power of @batch(1)
Most decorators handle metadata or validation.
But there’s one that actually changes deployment behavior — @batch()
.
When you create multiple resources in a loop, Bicep deploys them in parallel by default. That’s fast, but not always safe.
To start this first we need to create some very basic IaC, a resource group and a virtual network
Initial IaC - Virtual Network
|
|
Example:
|
|
If you’ve ever hit this error 👇
Each subnet creation updates the parent VNet’s metadata — and Azure only allows one update at a time. When ARM tries to deploy them all together, it collides with itself.
The Solution
Add the batchSize()
decorator to the createSubnets module:
|
|
The complete module, including the decorator:
|
|
Now subnets deploy sequentially, one at a time — avoiding the metadata lock.
You can even tune it (e.g., @batch(3)
), but for subnets, @batch(1)
is the safe bet.
Pro Tip:
Use batching any time you’re looping over resources that share a parent — VNets, App Service Plans, or Key Vaults.
Full List of Supported Decorators (2025)
Decorator | Purpose |
---|---|
@allowed([...]) | Restrict parameter values |
@batch(n) | Control parallel loop deployment |
@description('…') | Add human-readable info |
@discriminator('…') | Tagged union type handling |
@export() | Allow cross-file imports |
@metadata({…}) | Attach metadata (for tools) |
@minLength(n) / @maxLength(n) | String/array validation |
@minValue(n) / @maxValue(n) | Numeric validation |
@sealed() | Prevent typos in object keys |
@secure() | Mark as sensitive |
Bicep continues to evolve, so it’s always worth checking the official documentation for the latest supported decorators.
Wrapping Up
Decorators might not grab the headlines, but they make a huge difference in how clean, reliable, and maintainable your Bicep templates become. They turn quick scripts into professional-grade deployments — the kind you can hand off to a team and still sleep at night.
So next time you’re building parameters, outputs, or resource loops, don’t skip the @. Those small details turn good infrastructure into great automation — and your future self will thank you for it.