Workspaces for Dev/Test/Prod or other different environments

I have a question regarding Terraform workspaces. Lets say that you have one test, one dev and one production subscription in Azure. You want the same resources deployed to each one of these subscriptions, besides some minor details like different resource names.

On the following page:

It says the following:

" In particular, organizations commonly want to create a strong separation between multiple deployments of the same infrastructure serving different development stages (e.g. staging vs. production) or different internal teams. In this case, the backend used for each deployment often belongs to that deployment, with different credentials and access controls. Named workspaces are not a suitable isolation mechanism for this scenario."

So, the suggestions points to that you should have one separate Terraform configuration for each of the environments, with the exact same code? So if we need to update something, we need to update each of those configurations? Sounds tedious and quite counterproductive.

I’ve seen people using Terraform workspaces in Azure DevOps, in a dev/test/prod fashion. Are they doing it wrong and should they stop doing that immediately?

The following blog posts describe how you should set up your pipelines with a dev/test/prod using workspaces:

Especially the first link is quite interesting, as he at the very beginning states the following:

“The topic I have chosen is because of this post that I discovered recently: Recommended Practices. Hashicorp is recommending the use of workspaces to control different environments. Which is a change of recommendation from what I remember from February/March 2019.”

Do Hashicorp recommend using workspaces for different environments? Where does he get that from? Since the first link, from Terraform, is saying otherwise.

So what is a recommended design pattern here, if you have e.g. four different subscriptions in Azure, and want to create plan/deploy pipelines in Azure DevOps for all of these?

Is it to
Create one Terraform configuration for each one of them, take care of all of that administration and if you update one, you have to update all of them?

Create one workspace for each of them? Workspace a, b, c and d, and then just control their values via terraform.workspace interpolation?

Something completely else?

I’m thankful for all input here, since this topic confuses me. If you would recommend one option over another, please inform me as of why. What are the advantages, and why is that the best choice?

Thank you in advance!

There is no universal answer to this question, but the recommendation in the first article (on the Terraform website) is not to duplicate your entire configuration for each environment, but rather to write a separate root module for each environment, and use shared modules to represent the common details, as the subsequent paragraph says:

Instead, use one or more re-usable modules to represent the common elements, and then represent each instance as a separate configuration that instantiates those common elements in the context of a different backend. In that case, the root module of each configuration will consist only of a backend configuration and a small number of module blocks whose arguments describe any small differences between the deployments.

The full text of that section is describing a particular set of circumstances which is common and for which workspaces alone are a poor fit:

  • Each environment must have its own entirely separate backend configuration. Because multiple workspaces is a means to retain several distinct state snapshots in a single backend, the requirement to keep the backends distinct is in conflict with the use of workspaces.
  • The environments have significant structural differences, which are most easily expressed by Module Composition, rather than trying to write a single mega-config that represents all of the different permutations. For example, it seems pretty typical for a production environment to span across many regions while pre-production environments may use only one, or only two; we can use module composition to represent that difference by writing a shared module that represents what ought to exist in one region, and then instantiating that shared module many times in production but only once or twice in pre-production.

If those constraints don’t apply to you then you may find Terraform workspaces suitable for your problem, but unfortunately that is an engineering tradeoff you’ll need to make yourself because only you know the full set of technical, regulatory, and other constraints you’re operating under.

Thank you for your valuable input @apparentlymart, much appreciated.