TLDR; The best Infrastructure as Code tool for Azure Landing Zones depends less on features and more on organisational operating models. Teams should evaluate ownership boundaries, governance controls, deployment processes, recovery capabilities and existing investments before selecting Bicep or Terraform.
A few years ago, I joined what initially looked like a straightforward Azure Landing Zone engagement. The customer was expanding its Azure footprint, several new workloads were approaching the platform, and the existing environment had reached the point where stronger structure and governance were needed.
By the time I joined, one question had already started circulating between the platform team, infrastructure manager and senior stakeholders: Should we use Bicep or Terraform for the Landing Zone?
At first glance, it sounded like a reasonable place to start. The organisation was predominantly Azure, several engineers were comfortable with Bicep, and another part of the technology team was already using Terraform. During the first architecture discussion, one stakeholder asked, “We’re an Azure organisation. Wouldn’t Bicep make more sense?” An engineer responded, “We already use Terraform. Why introduce another Infrastructure as Code technology?”
Both positions were reasonable, but neither was enough to make the decision. That was when I suggested we temporarily stop comparing the tools.
We were asking the technology question too early
Instead of putting a Terraform-versus-Bicep comparison matrix on the screen, I drew a simplified Azure Landing Zone hierarchy. At the top were management groups and subscriptions. Beneath them sat networking, policy, RBAC, monitoring, security controls and application Landing Zones.
Then I started putting teams beside those capabilities. The platform team would manage management groups and subscription structure. The network team would operate the hub, firewall and enterprise connectivity. The security team wanted ownership of selected controls, while application teams would consume Landing Zones without owning the central platform.
The project manager looked at the diagram and asked, “So who owns the code?”
That question changed the conversation because ownership turned out to mean several different things. Who owns the resource operationally? Who maintains the code? Who can deploy changes? Who approves them? Who responds when something fails?
Those responsibilities do not always belong to the same team. A network team may own the hub operationally while the platform team maintains the deployment framework. A security team may define policy standards while another team manages the release process.
Once we separated resource ownership, code ownership and deployment responsibility, the discussion became much clearer. We were no longer comparing languages; we were defining an operating model.
Then we discovered it wasn't really greenfield
The project description had made the Landing Zone sound relatively new, but discovery showed a more complicated environment. Some resources had been created manually, others through PowerShell or ARM templates, and several teams were already using Terraform.
One architect asked whether we could simply build the new Landing Zone using Bicep and progressively move the existing estate underneath it. Technically, there were options, but I asked a different question: “What exactly do we mean by move?”
Were we talking about changing management group placement, introducing new policy inheritance, changing RBAC, bringing existing networks under a new deployment model, or rewriting resources that were already functioning?
Those are very different activities.
The customer had thought it was choosing a technology for a new platform. In reality, it was also deciding how much of the existing estate should eventually come under a consistent management model.
That made existing investment, migration effort and team capability part of the architecture decision. If a substantial estate was already managed successfully through Terraform, moving to Bicep would introduce retraining and migration cost. Equally, if the future platform was strongly Azure-native and the existing Terraform footprint was small, choosing Terraform purely because some Terraform already existed would also need justification.
A portal change started the drift conversation
A few days later, an engineer changed a network configuration directly in the Azure portal while troubleshooting a connectivity issue. The change was legitimate, but the repository had no context for why it had happened.
During the next review, someone asked, “What happens when the pipeline runs again?”
With Terraform, the broad model was familiar: configuration, Terraform state and the deployed environment are reconciled through the plan and apply lifecycle. Bicep works differently. It does not maintain a Terraform-style state file; Azure Resource Manager evaluates the deployment against the current state of Azure resources, with capabilities such as what-if helping preview changes in supported scenarios.
Those mechanisms are not equivalent, and I did not want the workshop to pretend they were.
Instead, I asked: What do we expect the team to do when Azure and source control no longer match?
The operations manager answered with the question that mattered most: “How do we know whether the change was intentional?”
That was the real issue. Drift detection is useful, but a difference does not automatically mean something is wrong. The team still needs a process to understand the change, decide whether it should remain and reconcile the approved state safely.
Removing one resource created a bigger discussion
During a later workshop, we removed a representative resource from the desired configuration. Almost immediately, someone asked, “If it isn’t in the code anymore, should Azure delete it?”
The platform engineer thought it probably should. The network engineer disagreed and asked what would happen if ownership was moving into the network team’s deployment. Another stakeholder suggested leaving the resource in Azure but stopping management from the original deployment.
All three behaviours could be valid.
Removing something from code is not automatically the same as deciding to delete it. A resource may be retired, remain in Azure but become unmanaged by the current deployment, or move into another team’s ownership boundary.
Terraform has its state-based lifecycle model. In an Azure-native design, Deployment Stacks can provide resource tracking and lifecycle controls for resources managed by the stack. We were careful, however, not to describe Deployment Stacks as “Bicep state.” They are a different Azure-native mechanism with their own capabilities and limitations.
The architectural question was more important: Does the lifecycle model reflect how this organisation expects ownership to work?
Protection wasn't really an IaC question
The platform manager later looked at the hub, firewall, monitoring platform and policy structure and asked, “What prevents an application team from accidentally changing one of these?”
That was primarily a governance and authorisation question.
We mapped the controls. Azure RBAC remained the primary mechanism for determining who could perform management operations. Azure Policy could enforce configuration requirements. Resource locks might be appropriate for selected critical resources. Deployment Stack deny settings could provide another control where that model fitted the requirement.
We also looked upstream. Were pull requests required? Were code owners defined? Were production approvals separated appropriately? Could the same person propose, approve and deploy a sensitive governance change?
The IaC choice was becoming part of the customer’s governance model, not just its deployment model.
Then security asked about the pipeline identity
Someone suggested assigning Owner to the deployment identity so the proof of concept could move faster. It would have simplified the deployment, but it would have proved very little about the intended production design.
Instead, we reduced permissions and deliberately allowed the pipeline to fail. Another engineer had to determine which permission was missing, at which scope and for which operation.
We also considered how the identity itself would be established. For modern CI/CD, federated workload identity or managed identity should generally be considered where appropriate rather than defaulting to long-lived client secrets.
The principle remained simple: the deployment identity should have the permissions it needs, at the scopes it needs, and no more.
Then we broke the deployment
One of the most useful exercises came when we deliberately caused a deployment to fail partway through. Several foundational components succeeded, but a later dependency failed.
Then we stopped.
The engineer who had written the implementation was not asked to recover it. Another engineer had to determine what had deployed, what had failed, what Azure’s actual state was and whether another deployment could run safely.
For Terraform, that meant understanding configuration, Azure resources, state, backend and locking. For Bicep, it meant understanding Azure Resource Manager deployment behaviour, current resource state, deployment history and any relevant lifecycle controls.
We were not trying to make the recovery experiences identical. We were testing whether someone other than the original author could understand what had happened and return the platform safely to the intended state.
That required pipeline logs, deployment history, Activity Logs and pull-request context. Recovery was not simply a deployment problem; it was an observability and supportability problem as well.
The decision was no longer "Bicep or Terraform?"
By this stage, developer familiarity was only one consideration among many. We were asking whether teams could operate independently without creating competing sources of truth, whether drift could be understood and reconciled, whether another engineer could recover a failure, and whether the pipeline could operate with least privilege.
We were also asking whether governance changes could be controlled according to their blast radius and whether new engineers could realistically learn and support the platform. Training effort, onboarding, recruitment, existing engineering experience and migration cost are all legitimate architecture concerns.
By the end of the engagement, we had changed the original question.
We were no longer asking, “Which technology is better?”
We were asking:
Which infrastructure management model best fits how this organisation intends to operate Azure?
A greenfield Azure-focused organisation may find Bicep very well aligned. An organisation already operating Terraform successfully may find Terraform fits more naturally. An Azure-only enterprise with a mature Terraform estate may also reasonably stay with Terraform if moving provides no measurable benefit.
And in larger organisations, the answer may not be one tool everywhere. Different platform domains can have different implementation boundaries if ownership, interfaces and lifecycle responsibilities remain clear.
We started with two technologies on a whiteboard. We finished with an operating model.
The IaC tool should follow the operating model rather than define it.
Before selecting Terraform or Bicep for an Azure Landing Zone, understand who owns the resources, who owns the code, who can deploy changes, how changes are approved, how drift is handled, how failures are recovered and whether the organisation can realistically support the platform over time.
Once those questions are clear, the technology decision becomes considerably more informed.
Even then, I would not make the final decision from a workshop alone. The next step is to test those assumptions in an environment that resembles the one the organisation will have to operate.
That is where Part 2 begins: with a practical proof of concept designed not simply to demonstrate that Bicep and Terraform can deploy an Azure Landing Zone, but to determine which approach the organisation can operate, govern, recover and evolve over the long term.


