Different Module Versions for Dev and Prod
We’ll cover how to use different versions of a module for the dev and prod environments.
What People Usually Do
First, let’s cover the approach people typically take. Usually, folks have a folder structure that represents the dev and prod environments. This results in a bunch of copy-and-paste. The entire dev and prod structure mirror each other. They then adjust a version number in the respective env folders. Here’s an example structure:
infra
├── dev
│ ├── example.tfvars
│ ├── main.tf
│ └── vars.tf
└── prod
├── example.tfvars
├── main.tf
└── vars.tf
The dev/main.tf
uses s3 bucket module version 2.6.0
module "bucket" {
source = "terraform-aws-modules/s3-bucket/aws"
version = "2.6.0"
}
The prod/main.tf
uses s3 bucket module version 2.5.0
module "bucket" {
source = "terraform-aws-modules/s3-bucket/aws"
version = "2.5.0"
}
While this may seem like a good way to approach it, it introduces a ton of duplication. The rest of the main.tf
contents will be duplicated. If you also have variables.tf
and outputs.tf
, those are also all duplicated.
Different Module Versions with Terraspace
Since Terraspace builds a Terraform project, you can control how to build the project. So you can dynamically set only the version and keep the rest of the code same. This dramatically reduces duplication.
To see how this can be achieved with Terraspace, here’s an example Terraspace project structure:
app
└── stacks
└── demo
├── main.tf
├── outputs.tf
└── variables.tf
The main.tf
looks could look like this:
app/stacks/demo/main.tf:
module "bucket" {
source = "terraform-aws-modules/s3-bucket/aws"
version = "2.5.0" # currently the same version for both dev and prod
}
Generate Helper
We can use helpers to dynamically control the version. Let’s generate a starter helper:
$ terraspace new helper demo --type stack --name version
create app/stacks/demo/config/helpers
create app/stacks/demo/config/helpers/version_helper.rb
$
The structure now looks like this:
app
└── stacks
└── demo
├── config
│ └── helpers
│ └── version_helper.rb
├── main.tf
├── outputs.tf
└── variables.tf
Write Custom Helper
We can add a custom version
helper with logic that decides which version to use.
app/stacks/bucket/config/helpers/version_helper.rb
module Terraspace::Module::Demo::VersionHelper
def version
map = {
dev: "2.6.0",
prod: "2.5.0",
}
map[Terraspace.env.to_sym] || "2.5.0"
end
end
Use Custom Helper
We can now use that helper method in main.tf
like so:
app/stacks/demo/main.tf:
module "s3-bucket" {
source = "terraform-aws-modules/s3-bucket/aws"
version = "<%= version %>"
}
Deploy
Now when deployed, dev will use version 2.6.0
$ TS_ENV=dev terraspace up demo # use version 2.6.0
$ cat .terraspace-cache/us-west-2/dev/stacks/demo/main.tf
module "s3-bucket" {
source = "terraform-aws-modules/s3-bucket/aws"
version = "2.6.0"
}
And prod will use 2.5.0.
$ TS_ENV=prod terraspace up demo # use version 2.5.0
$ cat .terraspace-cache/us-west-2/prod/stacks/demo/main.tf
module "s3-bucket" {
source = "terraform-aws-modules/s3-bucket/aws"
version = "2.5.0"
}
$
Since the Terraform project code is generated by Terraspace, we are able to only make the version different and avoided a lot of duplication.