SKILL.md, explained: the file is singular, the folder is plural
Why GitHub Copilot skills live in plural folders but singular SKILL.md files, how they load, and when supporting files are pulled in on demand.
The Infrastructure as Code (IaC) landscape has evolved dramatically over the past few years, with organizations increasingly adopting declarative approaches to manage their cloud resources. Two prominent players have emerged as frontrunners in this space: Azure Bicep and HashiCorp Terraform. Recently, OpenTofu has joined as a community-driven fork of Terraform, offering the same capabilities under open-source governance. While all these tools aim to solve the same fundamental problem (provisioning and managing infrastructure through code), they take different approaches to governance and platform focus.
After working extensively with both Bicep and Terraform across various projects and cloud environments, I’ve developed strong opinions about when to use each. This isn’t just another feature comparison; it’s a practical guide based on real-world experience, complete with examples, best practices, and honest assessments of each tool’s strengths and weaknesses, plus insights on when OpenTofu might be the right choice.
| Aspect | Bicep | Terraform | OpenTofu |
|---|---|---|---|
| Cloud Support | Azure only | Multi-cloud | Multi-cloud (same as Terraform) |
| Learning Curve | Gentle (for Azure devs) | Moderate | Identical to Terraform |
| State Management | Azure-managed | Manual/Remote | Manual/Remote (same as Terraform) |
| Syntax | Clean, intuitive | Verbose but consistent | Identical to Terraform |
| Features | Azure-focused | Full multi-cloud | Same feature set as Terraform |
| Community | Growing | Large | Emerging (Terraform-compatible) |
| Vendor | Microsoft | IBM (HashiCorp) | Linux Foundation |
| License | MIT | MPL 2.0 | MPL 2.0 |
| Best For | Azure-first teams | Multi-cloud environments | Open-source advocates who want Terraform |
Before diving into technical details, it’s important to understand the core philosophical differences between these tools:
Bicep represents Microsoft’s vision of Azure-native infrastructure management. It’s designed specifically for Azure, embracing the platform’s unique characteristics and providing deep integration with Azure Resource Manager (ARM). Think of it as the “native son” approach: built by Azure, for Azure.
Terraform embodies HashiCorp’s multi-cloud philosophy. It’s designed to be cloud-agnostic, treating all cloud providers as equals through its provider ecosystem. This is the “universal translator” approach: one language to rule them all.
OpenTofu is essentially Terraform with different governance. Since it’s a fork of Terraform, it shares identical syntax, features, and capabilities. The key difference is organizational: OpenTofu is managed by the Linux Foundation as a truly open-source project, while Terraform is now owned by IBM. From a technical standpoint, they’re virtually identical.
Bicep’s syntax feels refreshingly clean, especially if you’re coming from ARM templates. Here’s a simple storage account example:
param location string = resourceGroup().location
param storageAccountName string = 'mystorageacct${uniqueString(resourceGroup().id)}'
resource storageAccount 'Microsoft.Storage/storageAccounts@2024-01-01' = {
name: storageAccountName
location: location
sku: {
name: 'Standard_LRS'
}
kind: 'StorageV2'
properties: {
accessTier: 'Hot'
}
}
output storageAccountKey string = storageAccount.listKeys().keys[0].value
The beauty of Bicep syntax lies in its intuitive feel for Azure developers. Resource definitions read almost like natural language, while strong typing provides excellent IntelliSense support that makes development feel effortless. The automatic dependency management through symbolic references eliminates much of the complexity that comes with orchestrating infrastructure deployments.
Terraform’s HCL (HashiCorp Configuration Language) syntax is more verbose but consistent across all providers:
variable "location" {
description = "Azure region for resources"
type = string
default = "West Europe"
}
variable "resource_group_name" {
description = "Name of the resource group"
type = string
}
resource "azurerm_storage_account" "example" {
name = "mystorageacct${random_string.suffix.result}"
resource_group_name = var.resource_group_name
location = var.location
account_tier = "Standard"
account_replication_type = "LRS"
account_kind = "StorageV2"
access_tier = "Hot"
}
resource "random_string" "suffix" {
length = 8
special = false
upper = false
}
output "storage_account_key" {
value = azurerm_storage_account.example.primary_access_key
sensitive = true
}
Terraform’s strength lies in its consistency across providers and the rich ecosystem that has evolved around it. The same patterns and concepts apply whether you’re provisioning AWS EC2 instances, Azure storage accounts, or Kubernetes clusters. This consistency becomes invaluable when working across multiple platforms, though it comes at the cost of some Azure-specific optimizations.
Bicep shines when you’re all-in on Azure. It supports:
This tight integration means you’ll never wait for a provider update to use the latest Azure features. When Azure releases a new service, Bicep can use it immediately.
Terraform’s strength lies in its breadth:
If you’re working in a multi-cloud environment or need to manage resources beyond pure cloud infrastructure, Terraform’s ecosystem is unmatched.
One of Bicep’s most compelling features is no local state files. Azure Resource Manager handles all state management:
| ✅ Advantages | ❌ Limitations |
|---|---|
| No state file corruption or conflicts | Tied to Azure’s deployment model |
| Natural team collaboration without state locking | Less flexibility for complex deployment scenarios |
| Automatic cleanup of orphaned resources | Harder to manage resources across multiple Azure tenants |
| Built-in what-if operations for change preview | Limited to Azure Resource Manager capabilities |
Terraform’s state file approach provides fine-grained control:
| ✅ Advantages | ⚠️ Challenges |
|---|---|
| Complete visibility into managed resources | State file management complexity |
| Support for import operations | Potential for state corruption |
| Flexible backend options (S3, Azure Storage, Terraform Cloud) | Team collaboration requires careful state locking |
| Powerful state manipulation commands | Manual cleanup of orphaned resources |
💡 Key insight: Bicep deployments are generally faster for Azure resources, particularly for complex scenarios involving multiple interdependent resources.
Why Bicep is faster:
Terraform deployments can be slower, especially when managing large numbers of resources, but the gap has narrowed significantly with recent performance improvements.
🔍 Pro tip: Bicep provides superior error messages for Azure-specific issues. When something goes wrong, you get clear, actionable error messages that directly relate to Azure concepts.
Terraform’s error messages can be more cryptic, particularly when dealing with provider-specific issues. However, Terraform’s plan output is generally more detailed for understanding what changes will be applied.
Bicep shines brightest when you’re building solutions that live and breathe Azure. If your organization has made the strategic decision to standardize on Microsoft’s cloud platform, Bicep offers a development experience that feels natural and intuitive. Teams already familiar with ARM templates will find the transition almost effortless, while newcomers appreciate how directly Bicep concepts map to Azure resources.
The immediate access to new Azure features is another compelling reason to choose Bicep. When Microsoft releases new services or capabilities, they’re available in Bicep on day one—no waiting for third-party providers to catch up. This can be crucial for organizations that want to leverage cutting-edge Azure capabilities as soon as they’re available.
Key scenarios where Bicep excels:
// Example of a well-structured Bicep module
param environmentName string
param location string = resourceGroup().location
var tags = {
Environment: environmentName
ManagedBy: 'Bicep'
CreatedDate: utcNow('yyyy-MM-dd')
}
module networking 'modules/networking.bicep' = {
name: 'networking-deployment'
params: {
environmentName: environmentName
location: location
tags: tags
}
}
module compute 'modules/compute.bicep' = {
name: 'compute-deployment'
params: {
environmentName: environmentName
location: location
subnetId: networking.outputs.subnetId
tags: tags
}
}
// Example of a well-structured Bicep module following best practices
param environmentName string
param location string = resourceGroup().location
var tags = {
Environment: environmentName
ManagedBy: 'Bicep'
CreatedDate: utcNow('yyyy-MM-dd')
}
module networking 'modules/networking.bicep' = {
name: 'networking-deployment'
params: {
environmentName: environmentName
location: location
tags: tags
}
}
module compute 'modules/compute.bicep' = {
name: 'compute-deployment'
params: {
environmentName: environmentName
location: location
subnetId: networking.outputs.subnetId
tags: tags
}
}
Terraform becomes the clear winner when your infrastructure story extends beyond a single cloud provider. Whether you’re orchestrating resources across AWS, Azure, and Google Cloud, or integrating cloud services with on-premises infrastructure, Terraform’s provider ecosystem is unmatched. The consistent syntax and approach across all providers means your team can apply the same concepts and patterns regardless of the underlying platform.
The mature ecosystem surrounding Terraform is another significant advantage. With thousands of community-contributed modules, chances are someone has already solved the infrastructure challenge you’re facing. This can dramatically accelerate development time, though it’s important to thoroughly validate any modules you incorporate into your infrastructure.
Terraform also offers more sophisticated state management capabilities, which becomes crucial as your infrastructure grows in complexity. The ability to manipulate state, import existing resources, and use advanced features like workspaces provides the flexibility needed for enterprise-scale deployments.
Terraform excels in these scenarios:
# Example of a well-structured Terraform configuration
terraform {
required_version = ">= 1.12.2"
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "~> 4.34.0"
}
}
backend "azurerm" {
resource_group_name = "terraform-state-rg"
storage_account_name = "terraformstatestorage"
container_name = "tfstate"
key = "prod.terraform.tfstate"
}
}
variable "environment" {
description = "The deployment environment"
type = string
validation {
condition = contains(["dev", "staging", "prod"], var.environment)
error_message = "Environment must be dev, staging, or prod."
}
}
locals {
common_tags = {
Environment = var.environment
ManagedBy = "Terraform"
Project = "MyProject"
}
}
module "networking" {
source = "./modules/networking"
environment = var.environment
tags = local.common_tags
}
module "compute" {
source = "./modules/compute"
environment = var.environment
subnet_id = module.networking.subnet_id
tags = local.common_tags
}
If you’re already working with Azure, Bicep has a remarkably gentle learning curve. The syntax is intuitive, the tooling is excellent, and the concepts map directly to Azure resources you already understand.
Time to productivity: 1-2 weeks for basic competency, 1-2 months for advanced scenarios.
Terraform requires more upfront investment to understand concepts like providers, state, workspaces, and the HCL language itself. However, this investment pays dividends if you’re working across multiple platforms.
Time to productivity: 2-4 weeks for basic competency, 2-3 months for advanced multi-cloud scenarios.
While both Bicep and Terraform are free to use, the total cost of ownership tells a more nuanced story. These costs extend far beyond software licensing to include learning curves, operational overhead, and long-term maintenance.
Bicep’s cost advantages stem from simplicity and integration. Azure-focused teams can become productive faster, reducing the time and cost associated with training and onboarding. The elimination of state file management removes an entire category of operational complexity, reducing both infrastructure costs and the human effort required to maintain reliable deployments. For organizations already invested in Microsoft tooling, Bicep integrates seamlessly with existing development workflows, minimizing additional tool licensing and training costs.
Terraform’s costs are front-loaded but offer long-term flexibility benefits. The initial learning investment is higher, especially for teams new to infrastructure as code concepts. State management requires additional infrastructure and operational processes, adding complexity and cost. However, these investments pay dividends in multi-cloud scenarios where Terraform’s consistency can actually reduce overall complexity compared to learning multiple cloud-specific tools.
Organizations should also consider the cost of potential vendor lock-in. While Bicep ties you to Azure, this might align perfectly with your business strategy. Terraform provides more flexibility but requires ongoing investment in maintaining multi-provider expertise.
The choice between Bicep and Terraform often comes down to organizational context rather than pure technical merit. I’ve seen technically superior solutions fail because they didn’t align with team capabilities, organizational culture, or long-term strategy.
Bicep succeeds when organizations embrace Azure-first thinking. If your company has made the strategic decision to standardize on Microsoft technologies, choosing Bicep reinforces that decision and provides a more integrated development experience. Teams that already understand Azure concepts will be productive with Bicep much faster than learning Terraform’s abstractions.
Terraform thrives in organizations that value flexibility and want to avoid vendor lock-in. Companies that operate in regulated industries, work with multiple cloud providers, or have complex hybrid environments often find Terraform’s provider ecosystem invaluable. The learning investment pays dividends when you need to manage resources across different platforms with consistent tooling.
The size and structure of your team also influences the decision. Smaller, Azure-focused teams often prefer Bicep’s simplicity and integration with Microsoft tooling. Larger organizations with dedicated infrastructure teams and diverse platform requirements typically benefit from Terraform’s flexibility and ecosystem.
From a career development perspective, both tools offer valuable skills, but with different market dynamics. Terraform skills are more transferable across organizations and cloud providers, making it attractive for consultants and engineers who change roles frequently. Bicep expertise, while more specialized, is highly valued in Microsoft-centric organizations and can complement broader Azure architecture skills.
Consider your team’s current expertise and career goals. If your developers are already deep in the Microsoft ecosystem, Bicep represents a natural progression. If your team works across multiple platforms or wants to maintain cloud-agnostic skills, Terraform provides broader market applicability.
For large-scale Azure deployments, both tools handle complexity well, but differently:
Bicep excels at:
Terraform excels at:
Both tools integrate well with modern DevOps practices:
Bicep CI/CD strengths:
Terraform CI/CD strengths:
After years of working with both tools, here’s my decision framework:
flowchart TD
A[Starting IaC Journey] --> B{Azure Only?}
B -->|Yes| C{Team familiar with ARM?}
B -->|No| D{Open Source Priority?}
C -->|Yes| E[Choose Bicep]
C -->|No| F{Want simplicity?}
F -->|Yes| E
F -->|No| G[Consider Terraform]
D -->|Yes| H[Choose OpenTofu]
D -->|No| I{IBM concerns?}
I -->|Yes| H
I -->|No| J[Choose Terraform]
style E fill:#0078d4,color:#fff
style H fill:#ff6b35,color:#fff
style J fill:#623ce4,color:#fff
In larger organizations, I’ve seen successful implementations using both tools:
This approach leverages each tool’s strengths while minimizing their weaknesses.
Both tools are rapidly evolving:
It’s impossible to discuss Terraform’s future without addressing the elephant in the room: IBM’s acquisition of HashiCorp in 2024. This major change brings both opportunities and concerns that organizations need to consider when making long-term IaC decisions.
If you’re choosing between Bicep and Terraform today, the IBM acquisition adds a new variable to consider:
The acquisition is still relatively recent, and its full implications won’t be clear for some time. However, it’s a reminder that no tool exists in a vacuum, and vendor relationships matter when making infrastructure decisions.
Speaking of vendor concerns, it’s worth mentioning OpenTofu, the open-source fork of Terraform that emerged in response to HashiCorp’s licensing changes. Maintained by the Linux Foundation, OpenTofu is essentially Terraform with different governance - it shares the same syntax, features, and capabilities.
Why consider OpenTofu:
Current considerations:
For organizations concerned about vendor control or licensing costs, OpenTofu adds a third path to consider alongside Bicep and Terraform. It’s particularly appealing if you value open-source principles and want to avoid potential future licensing surprises.
While this post focuses on the declarative configuration language approach (Bicep, Terraform, OpenTofu), it’s worth acknowledging that other IaC paradigms exist:
Pulumi takes a different approach entirely, using general-purpose programming languages (TypeScript, Python, Go, C#) instead of domain-specific languages. This appeals to developers who prefer familiar programming constructs like loops, conditionals, and functions over declarative configurations.
AWS CDK, Azure CDK for Terraform, and similar tools also use programming languages but compile to other IaC formats (CloudFormation, Terraform) rather than running directly.
These imperative approaches have their own trade-offs around testability, debugging, and team collaboration that deserve a dedicated comparison. For this post, I’ve focused on the declarative DSL ecosystem since that’s where most organizations start their IaC journey.
Choosing between Bicep, Terraform, and OpenTofu isn’t just a technical decision. It’s a strategic one that affects your team’s productivity, your organization’s flexibility, and your long-term infrastructure management approach.
Bicep represents focused specialization: deep, native integration with Azure that provides excellent developer experience and immediate access to Azure innovations. If you’re building on Azure and plan to stay there, Bicep’s focused approach pays dividends in team productivity and reduced complexity.
Terraform embodies flexible standardization: one tool, one workflow, across all your infrastructure needs. If you’re in a multi-cloud world or value the flexibility to change direction, Terraform’s ecosystem and proven track record make it a reliable choice, though the IBM acquisition adds uncertainty.
OpenTofu offers open-source assurance: for teams that prioritize community governance and want to avoid vendor dependencies, it provides Terraform compatibility without the corporate overhead.
The reality is that all these tools are excellent at what they do. The choice comes down to understanding your organization’s needs, constraints, risk tolerance, and long-term strategy. There’s no wrong choice here, only choices that are more or less aligned with your specific context.
What matters most is picking one, learning it well, and building great infrastructure with it. The best IaC tool is the one your team actually uses effectively, not the one with the most features on paper.
| Tool | Best for | Key advantage | Main concern |
|---|---|---|---|
| 🔵 Bicep | Azure-focused teams | Native integration, no state files | Limited to Azure only |
| 🟣 Terraform | Multi-cloud environments | Mature ecosystem, broad provider support | IBM acquisition uncertainty |
| 🟠 OpenTofu | Open-source advocates | Community governance, vendor independence | Smaller ecosystem |
🎯 Bottom line: Choose Bicep for Azure simplicity, Terraform for multi-cloud maturity, or OpenTofu for open-source peace of mind. All are solid choices when used appropriately.
What’s been your experience with Bicep and Terraform? I’d love to hear about your real-world usage patterns and any challenges you’ve encountered. Share your thoughts in the comments below or reach out to me directly.
Start the conversation