Are seperate terraform root modules possible/advised?

Is it possible to organize my terraform code like the following, with each module running it’s own terraform apply and having it’s own state file, whilst maintaining dependencies between them?

product-feed
├── infrastructure
│   └── main.tf
shared
├── infrastructure
│   └── main.tf

An example dependency would be…

shared → infrastructure → main.tf

resource "azurerm_user_assigned_identity" "identity" {
  location            = data.azurerm_resource_group.rg.location
  name                = "pip-exec-identity"
  resource_group_name = data.azurerm_resource_group.rg.name
}

product-feed → infrastructure → main.tf

data "azurerm_user_assigned_identity" "identity" {
  name                = "pip-exec-identity"
  resource_group_name = data.azurerm_resource_group.rg.name
}

I have a CD pipeline with 2 stages - stage A deploys ‘shared’ and stage B deploys ‘product-feed’.

The problem is there is no real dependency modelled here and I’m relying on the pipeline to stitch things together. If the above is added in the same commit and a terraform plan is ran for both stages, the product-feed stage will just fail as it won’t be able to resolve the data block which doesn’t yet exist.

Is there a better way to do this that doesn’t involve bundling everything back together? There are certain non-terraform things I would like to do between these deployments - i.e. after A but before B

Hi @Konnor5092,

Indeed, with a system design like what you’ve showed you would need to rely on something outside of Terraform to deal with the dependency ordering between these two configurations, since Terraform can only see that the second one has an external dependency (the data block) but cannot determine what other subsystem is responsible for the existence of that object. (It might not even be managed by Terraform!)

Solving this with features of the automation system that Terraform is running in is the typically answer, since (as seems to be a requirement for you) that allows the dependency graph to include actions that are not driven directly by Terraform too.

The capabilities of different automation systems are not equivalent but the general idea I see folks aim to model is:

  • Each time an apply job from upstream completes, arrange to trigger planning for all of the direct downstreams. This might just detect “no changes” if the upstream change didn’t affect the downstreams, but if it does detect needed changes then you can be proactively notified about them.
  • During initial system setup the downstream plans will fail until the upstreams have been applied for the first time. There isn’t really a compelling answer for this one, but if you happen to know which of the configurations are at the “root” (i.e. they have no upstream dependencies) then you can apply those ones first and then have the previous rule kick off another round of planning for the next tier of dependencies.

What you’re considering here is the main tradeoff with deciding what should be together in the same Terraform configuration and what should be separate. Keeping things together allows Terraform alone to manage the dependencies but forces you to always update everything all at once without any intermediate steps. Splitting it up gives you more flexibility, but with that flexibility comes the additional responsibility of orchestrating the multiple separate Terraform runs in the layer above.

Ooof…nasty.

This begs the question, should terraform plans without applys ever be part of a CI pipeline? Or at least the CI part of a CI/CD pipeline.

Seems a bit chicken and egg to me - You want to plan before you deploy, but you need to have deployed before you get an accurate plan.