{"id":13505871,"url":"https://github.com/0xDones/tfgen","last_synced_at":"2025-03-30T00:31:46.951Z","repository":{"id":38215538,"uuid":"453183173","full_name":"0xDones/tfgen","owner":"0xDones","description":"Terraform code generator for consistent codebase and DRY","archived":false,"fork":false,"pushed_at":"2024-07-28T19:19:45.000Z","size":115,"stargazers_count":85,"open_issues_count":6,"forks_count":13,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-03-28T17:09:17.879Z","etag":null,"topics":["cli","devtools","terraform","terragrunt"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/0xDones.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-01-28T18:56:08.000Z","updated_at":"2025-03-19T14:28:59.000Z","dependencies_parsed_at":"2024-04-11T03:00:08.301Z","dependency_job_id":"7a2708df-a3b1-4b68-959c-00e46103b994","html_url":"https://github.com/0xDones/tfgen","commit_stats":null,"previous_names":["0xdones/tfgen"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/0xDones%2Ftfgen","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/0xDones%2Ftfgen/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/0xDones%2Ftfgen/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/0xDones%2Ftfgen/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/0xDones","download_url":"https://codeload.github.com/0xDones/tfgen/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246262491,"owners_count":20749170,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cli","devtools","terraform","terragrunt"],"created_at":"2024-08-01T00:01:15.892Z","updated_at":"2025-03-30T00:31:41.934Z","avatar_url":"https://github.com/0xDones.png","language":"Go","funding_links":[],"categories":["Tools"],"sub_categories":["Community providers"],"readme":"# tfgen - Terraform boilerplate generator\n\n[![Maintenance](https://img.shields.io/badge/Maintained%3F-yes-green.svg)](https://GitHub.com/Naereen/StrapDown.js/graphs/commit-activity)\n[![GitHub go.mod Go version of a Go module](https://img.shields.io/github/go-mod/go-version/0xDones/tfgen.svg)](https://github.com/0xDones/tfgen)\n[![GitHub stars](https://img.shields.io/github/stars/0xDones/tfgen.svg?style=social\u0026label=Star)](https://github.com/0xDones/tfgen/stargazers/)\n\nTerragrunt alternative to keep your Terraform code consistent and DRY\n\n## Overview\n\n### What is tfgen\n\n`tfgen` is useful for maintaining and scaling a [Terraform Monorepo](https://github.com/0xDones/terraform-monorepo-example), in which you provision resources in a multi-environment/account setup. It is designed to create consistent Terraform definitions, like backend (with dynamic key), provider, and variables for each environment/account, as defined in a set of YAML configuration files.\n\n### Why tfgen\n\n[Terragrunt](https://github.com/gruntwork-io/terragrunt) - a thin wrapper for Terraform that provides extra tools for working with multiple Terraform modules - is a great tool and inspired me a lot to create `tfgen`, but instead of being a wrapper for the Terraform binary, `tfgen` just creates Terraform files from templates and doesn't interact with Terraform at all. Terraform will be used independently on your local environment or in your CI system to deploy the resources.\n\n- This is not just a tool, it's a way of doing things\n- Keep your Terraform configuration consistent across the environments\n- Reduce the risk of making mistakes while copying+pasting your backend, provider, and other common Terraform definitions\n- Increase your productivity\n- Scale your mono repo following the same pattern across the modules\n\n### Features\n\n- Builtin functionality to provide the remote state key dynamically\n- YAML file configuration\n- Templates are parsed using `Go templates`\n\n## Getting Started\n\n### Prereqs\n\n- Docker or Go\n\n### Installation\n\n```bash\ngit clone --depth 1 git@github.com:0xDones/tfgen.git\ncd tfgen\n\n# Using Docker\ndocker run --rm -v $PWD:/src -w /src -e GOOS=darwin -e GOARCH=amd64 golang:alpine go build -o bin/tfgen\n\n# Using Go\ngo build -o bin/tfgen\n\nmv bin/tfgen /usr/local/bin\n```\n\n__Note:__ when building using Docker, change `GOOS=darwin` to `GOOS=linux` or `GOOS=windows` based on your system\n\n## Usage\n\n### Basic Usage\n\n```bash\n$ tfgen help\ntfgen is a devtool to keep your Terraform code consistent and DRY\n\nUsage:\n  tfgen [command]\n\nAvailable Commands:\n  clean       clean templates from the target directory\n  completion  Generate the autocompletion script for the specified shell\n  exec        Execute the templates in the given target directory\n  help        Help about any command\n\nFlags:\n  -h, --help      help for tfgen\n  -v, --verbose   verbose output\n\nUse \"tfgen [command] --help\" for more information about a command.\n```\n\n### Configuration files\n\nThe configuration files are written in YAML and have the following structure:\n\n```yaml\n---\nroot_file: bool\nvars:\n  var1: value1\n  var2: value2\ntemplate_files:\n  template1.tf: |\n    template content\n  template2.tf: |\n    template content\n```\n\n#### How config files are parsed\n\n__tfgen__ will recursively look for all `.tfgen.yaml` files from the target directory up to the parent directories until it finds the __root config file__, if it doesn't find the file it will exit with an error. All the other files found on the way up are merged into the root config file, and the __inner config file has precedence over the outer__.\n\nWe have two types of configuration files:\n\n1. Root config\n2. Environment specific config\n\n#### Root config\n\nIn the root config file, you can set variables and templates that can be reused across all environments. You need at least 1 root config file.\n\n```yaml\n# infra-live/.tfgen.yaml\n---\nroot_file: true\nvars:\n  company: acme\ntemplate_files:\n  _backend.tf: |\n    terraform {\n      backend \"s3\" {\n        bucket         = \"my-state-bucket\"\n        dynamodb_table = \"my-lock-table\"\n        encrypt        = true\n        key            = \"{{ .Vars.tfgen_state_key }}/terraform.tfstate\"\n        region         = \"{{ .Vars.aws_region }}\"\n        role_arn       = \"arn:aws:iam::{{ .Vars.aws_account_id }}:role/terraformRole\"\n      }\n    }\n  _provider.tf: |\n    provider \"aws\" {\n      region = \"{{ .Vars.aws_region }}\"\n      allowed_account_ids = [\n        \"{{ .Vars.aws_account_id }}\"\n      ]\n    }\n  _vars.tf: |\n    variable \"env\" {\n      type    = string\n      default = \"{{ .Vars.env }}\"\n    }\n```\n\n\u003e Note that `aws_region`, `aws_account`, and `env` are variables that you need to provide in the environment-specific config. `tfgen_state_key` is provided by the `tfgen`, it will be explained below.\n\n#### Environment specific config\n\nIn the environment-specific config file (non-root), you can pass additional configuration, or override configuration from the root config file. You can have multiple specific config files, all of them will be merged into the root one.\n\n```yaml\n# infra-live/dev/.tfgen.yaml\n---\nroot_file: false\nvars:\n  aws_account_id: 111111111111\n  aws_region: us-east-1\n  env: dev\n\n# infra-live/prod/.tfgen.yaml\n---\nroot_file: false\nvars:\n  aws_account_id: 222222222222\n  aws_region: us-east-2\n  env: prod\ntemplate_files:\n  additional.tf: |\n    # I'll just be created on modules inside the prod folder\n```\n\n### Provided Variables\n\nThese variables are automatically injected into the templates:\n\n- `tfgen_state_key`: The path from the root config file to the target directory\n\n## Practical Example\n\n### Repository Structure\n\nThe [terraform-monorepo-example](https://github.com/0xDones/terraform-monorepo-example) repository can be used as an example of how to structure your repository to leverage `tfgen` and also follow Terraform best practices.\n\n```md\n.\n├── infra-live\n│   ├── dev\n│   │   ├── networking\n│   │   ├── s3\n│   │   ├── security\n│   │   ├── stacks\n│   │   └── .tfgen.yaml     # Environment specific config\n│   ├── prod\n│   │   ├── networking\n│   │   ├── s3\n│   │   ├── security\n│   │   ├── stacks\n│   │   └── .tfgen.yaml     # Environment specific config\n│   └── .tfgen.yaml         # Root config file\n└── modules\n    └── my-custom-module\n```\n\nInside our `infra-live` folder, we have two environments, dev and prod. They are deployed in different aws accounts, and each one has a different role that needs to be assumed in the provider configuration. Instead of copying the files back and forth every time we need to create a new module, we'll let `tfgen` create it for us based on our configuration defined on the `.tfgen.yaml` config files.\n\n### Running the `exec` command\n\nLet's create the common files to start writing our Terraform module\n\n```bash\n# If you didn't clone the example repo yet\ngit clone git@github.com:0xDones/terraform-monorepo-example.git\ncd terraform-monorepo-example\n\n# Create a folder for our new module\nmkdir -p infra-live/dev/s3/dev-tfgen-bucket\ncd infra-live/dev/s3/dev-tfgen-bucket\n\n# Generate the files\ntfgen exec .\n\n# Checking the result (See Output section)\ncat _backend.tf _provider.tf _vars.tf\n```\n\nThis execution will create all the files inside the working directory, executing the templates and passing in all the variables declared in the config files.\n\n### Output\n\nThis will be the content of the files created by `tfgen`:\n\n#### _backend.tf\n\n```hcl\nterraform {\n  backend \"s3\" {\n    bucket         = \"my-state-bucket\"\n    dynamodb_table = \"my-lock-table\"\n    encrypt        = true\n    key            = \"dev/s3/dev-tfgen-bucket/terraform.tfstate\"\n    region         = \"us-east-1\"\n    role_arn       = \"arn:aws:iam::111111111111:role/terraformRole\"\n  }\n}\n```\n\n#### _provider.tf\n\n```hcl\nprovider \"aws\" {\n  region = \"us-east-1\"\n  allowed_account_ids = [\n    \"111111111111\"\n  ]\n}\n```\n\n#### _vars.tf\n\n```hcl\nvariable \"env\" {\n  type    = string\n  default = \"dev\"\n}\n```\n\n## Next steps\n\nAfter creating the common Terraform files, you'll probably start writing your `main.tf` file. So at this point, you already know what to do.\n\n```bash\nterraform init\n\nterraform plan -out tf.out\n\nterraform apply tf.out\n```\n\n## Related\n\n- [terraform-monorepo-example](https://github.com/0xDones/terraform-monorepo-example) - Example repo used in the tutorial\n- [Terragrunt](https://github.com/gruntwork-io/terragrunt) - Tool that inspired me to create `tfgen`\n\nHave fun!\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F0xDones%2Ftfgen","html_url":"https://awesome.ecosyste.ms/projects/github.com%2F0xDones%2Ftfgen","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F0xDones%2Ftfgen/lists"}