Bicep Tips and Tricks | #10 | Authoring Practices

Problem Space

As Bicep adoption grows, so does the complexity of the environments and teams using it. Without clear authoring practices, Bicep codebases can quickly become inconsistent, hard to maintain, and error-prone. In this post I wanted to share some practical authoring practices and anti-patterns to help you and your team write better Bicep code.

Why Define and Stick to Your Authoring Practices

Defining and following authoring practices ensures:

  • Consistency across your codebase and team
  • Easier onboarding for new contributors
  • Fewer errors and less technical debt
  • Improved maintainability and clarity

Below are some key practices and common anti-patterns to consider.


Authoring Practices

1. Folder Structure

Organise your Bicep files in a logical folder structure. For example, group modules by resource type or deployment context. This makes navigation and reuse easier:

├── modules/
│   ├── storage/
│   └── networking/
├── main.bicep
├── parameters/

2. Template Structure

Keep your templates clean and modular. Use modules for reusable components, and keep your main entry point focused on orchestration. Avoid putting everything in a single file.

3. Well Defined Names

Use clear, descriptive names for resources, parameters, and variables. Avoid abbreviations that aren’t widely understood. For example, prefer storageAccountName over saName.

4. Descriptions

Add descriptions to parameters, outputs, and resources. This helps users understand intent and usage:

@description('Configurable name for the application storage account')
param storageAccountName string

5. Comments

Use comments to explain why something is done, not what is done. Avoid echoing the code. Good comments provide context or rationale.

6. Constraints and Metadata

Leverage allowed values, min/max length, and metadata to enforce constraints and provide guidance:

@minLength(3)
@maxLength(24)
@allowed([ 'dev' 'test' 'prod' ])
param environment string

Make sure to use these where there is a specific need, over constraining parameters can equally cause issues.

7. Contracts

Define clear contracts for your modules: what parameters are required, what outputs are provided, and what assumptions are made. Document these in the module and in a README.

8. README

Modules and major orchestrating templates should have a README explaining its purpose and usage. This is invaluable for onboarding and reuse.

9. Bicep Linting

Use Bicep linting as part of your authoring workflow to catch issues early and enforce consistency. Define team linting rules in bicepconfig.json, run lint checks locally during development, and enforce them in CI to prevent low-quality or non-compliant templates from being merged.

10. AI-Generated Templates and Conformance

If you are using AI to generate Bicep, treat your authoring practices as executable guardrails rather than optional guidance.

Start by defining a clear generation contract in your prompt and repository standards:

  • Require a specific folder structure and file naming convention
  • Require module contracts (documented params/outputs and assumptions)
  • Require descriptions, meaningful names, and no dead code
  • Require lint-clean output before a template is considered complete

Then enforce conformance automatically in CI:

  • Validate formatting and linting on every pull request
  • Fail builds when lint rules are violated
  • Optionally add policy checks (for example, naming, locations, and SKUs)
  • Require human review for architectural decisions, not just syntax correctness

Finally, use a feedback loop. When reviewers find repeated AI mistakes, update your prompt template, lint configuration, and module examples so the next generation cycle improves by default.


Anti-Patterns

1. Premature Abstraction

Don’t create modules or abstractions before you have a real need. Over-abstraction leads to unnecessary complexity and maintenance overhead.

2. Over-Specification

Avoid making every resource parameter configurable if it’s not needed. Too many parameters can confuse users and make templates harder to use.

3. Echo Comments

Comments that simply restate the code add no value. For example:

// Set the storage account name
param storageAccountName string

Instead, explain why a value is needed or any constraints.

4. Dead Code

Remove unused parameters, variables, and resources. Dead code clutters templates and can cause confusion or errors.

5. Generic Copy-Paste Documentation

Avoid boilerplate documentation that doesn’t reflect the actual template. Tailor docs and comments to the specific module or resource.

6. Poorly Defined Names

Names like var1 or resource2 make templates hard to understand. Use meaningful, descriptive names everywhere.


Conclusion

Establishing and following authoring practices for Bicep will help your team deliver infrastructure as code that is robust, maintainable, and easy to understand. Avoid common anti-patterns, and invest in clarity and documentation.

For the original version of this post see Andrew Wilson's personal blog at Bicep Tips and Tricks | #10 | Authoring Practices