{"id":16139165,"url":"https://github.com/jdolitsky/tq","last_synced_at":"2026-03-15T10:04:34.938Z","repository":{"id":225243598,"uuid":"765450628","full_name":"jdolitsky/tq","owner":"jdolitsky","description":"jq for .tf files (Terraform/OpenTofu)","archived":false,"fork":false,"pushed_at":"2024-03-27T17:57:39.000Z","size":148,"stargazers_count":26,"open_issues_count":0,"forks_count":3,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-03-29T13:11:21.517Z","etag":null,"topics":["hcl","jq","opentofu","terraform","tf"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jdolitsky.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":"2024-03-01T00:05:16.000Z","updated_at":"2025-03-02T04:16:30.000Z","dependencies_parsed_at":"2024-03-01T01:29:24.414Z","dependency_job_id":"71f50b0e-a1dd-4d01-81a5-65ea23ab205e","html_url":"https://github.com/jdolitsky/tq","commit_stats":null,"previous_names":["jdolitsky/tq"],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jdolitsky%2Ftq","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jdolitsky%2Ftq/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jdolitsky%2Ftq/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jdolitsky%2Ftq/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jdolitsky","download_url":"https://codeload.github.com/jdolitsky/tq/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":249795202,"owners_count":21326777,"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":["hcl","jq","opentofu","terraform","tf"],"created_at":"2024-10-09T23:47:42.036Z","updated_at":"2026-03-15T10:04:34.907Z","avatar_url":"https://github.com/jdolitsky.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# tq\n\n![build status](https://github.com/jdolitsky/tq/actions/workflows/build.yaml/badge.svg)\n\n---\n\n\u003cp align=\"center\"\u003e\n\u003cimg align=\"center\" alt=\"tq\" width=\"250\" src=\"./tq.png\"\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\njq for .tf files (Terraform/OpenTofu)\n\u003c/p\u003e\n\n---\n\n## Install\n\n```\ngo install github.com/jdolitsky/tq\n```\n\n_Note: requires `jq` (shells out to it under the hood)_\n\n## Usage\n\nIf the queried object is able to be parsed as a .tf file, it\nwill be returned as such. If not, output will fall back to the JSON representation.\n\nFor the .tf files in the usage examples, please refer to the\n[examples](./examples/) directory.\n\n### Example: Extract values\n\n```sh\ntq '.body.blocks[] | select(.type == \"locals\").attributes.ami' examples/aws.tf\n```\n\nOutput:\n\n```\n\"ami-830c94e3\"\n```\n\n### Example: Overwrite arguments for multiple resources\n\n```sh\ntq '.body.blocks[] |= if (\n  .type == \"resource\" and\n  .labels[0] == \"aws_instance\"\n) then (\n  .attributes.instance_type = \"\\\"t2.medium\\\"\"\n) else . end' examples/aws.tf\n```\n\nOutput:\n\n```hcl\nlocals {\n  ami = \"ami-830c94e3\"\n}\n\nresource \"aws_instance\" \"app_server_a\" {\n  ami           = local.ami\n  instance_type = \"t2.medium\"\n}\n\nresource \"aws_instance\" \"app_server_b\" {\n  ami           = local.ami\n  instance_type = \"t2.medium\"\n}\n\n```\n\n### Example: Delete resources\n\n```sh\ntq 'del(.body.blocks[] | select(\n  .type != \"resource\" or\n  .labels[0] != \"aws_instance\" or\n  .labels[1] != \"app_server_a\"\n))' examples/aws.tf\n```\n\nOutput:\n\n```hcl\nresource \"aws_instance\" \"app_server_a\" {\n  ami           = local.ami\n  instance_type = \"t2.micro\"\n}\n```\n\n### Example: Add a resource\n\n```sh\ntq '.body.blocks += [{\n  type: \"resource\",\n  labels: [\n    \"aws_instance\",\n    \"app_server_c\"\n  ],\n  attributes: {\n    ami: \"local.ami\",\n    instance_type: \"\\\"t2.large\\\"\",\n  }\n}]' examples/aws.tf\n```\n\nOutput:\n\n```hcl\nlocals {\n  ami = \"ami-830c94e3\"\n}\n\nresource \"aws_instance\" \"app_server_a\" {\n  ami           = local.ami\n  instance_type = \"t2.micro\"\n}\n\nresource \"aws_instance\" \"app_server_b\" {\n  ami           = local.ami\n  instance_type = \"t2.small\"\n}\n\nresource \"aws_instance\" \"app_server_c\" {\n  ami           = local.ami\n  instance_type = \"t2.large\"\n}\n\n```\n\n## Serialization Format\n\nThis repo also provides 2 extra tools, `tf2json` and `json2tf` which can be used to convert between .tf and JSON.\nYou can use the following command to install them:\n\n```\ngo install github.com/jdolitsky/tq/extras/{tf2json,json2tf}\n```\n\nUsing `tf2json` (and `jq`), you can inspect the schema of the serialialization format used by `tq`:\n\n```\ntf2json examples/aws.tf | jq\n```\n\nOutput:\n\n```json\n{\n  \"body\": {\n    \"blocks\": [\n      {\n        \"type\": \"locals\",\n        \"labels\": [],\n        \"attributes\": {\n          \"ami\": \"\\\"ami-830c94e3\\\"\"\n        },\n        \"body\": {\n          \"blocks\": []\n        }\n      },\n      {\n        \"type\": \"resource\",\n        \"labels\": [\n          \"aws_instance\",\n          \"app_server_a\"\n        ],\n        \"attributes\": {\n          \"ami\": \"local.ami\",\n          \"instance_type\": \"\\\"t2.micro\\\"\"\n        },\n        \"body\": {\n          \"blocks\": []\n        }\n      },\n      {\n        \"type\": \"resource\",\n        \"labels\": [\n          \"aws_instance\",\n          \"app_server_b\"\n        ],\n        \"attributes\": {\n          \"ami\": \"local.ami\",\n          \"instance_type\": \"\\\"t2.small\\\"\"\n        },\n        \"body\": {\n          \"blocks\": []\n        }\n      }\n    ]\n  }\n}\n```\n\nThe following diagram attempts to clarify the data structure:\n\n\u003cimg width=\"500\" src=\"./diagram.png\"\u003e\n\u003c/p\u003e\n\nThe reason this format was chosen is to map as closely as possible to\nthe concepts found in the [`github.com/hashicorp/hcl/v2/hclwrite`](https://pkg.go.dev/github.com/hashicorp/hcl/v2/hclwrite)\nGo library which is used to parse and generate .tf.\n\n## Caveats\n\n- There is not currently support for comments, meaning any comments on the original input are removed from the resulting HCL output\n- In order to maintain deterministic output, all attributes (module arguments etc.) are alphabetically sorted, which may result in unexpected diffs\n- All attribute values are strings (the `attributes` field is a `map[string]string`). This is required  due to how the underlying libraries are used. For this purpose, real strings must be double quoted (e.g. `\"\\\"t2.micro\\\"\"`) and non-strings (of any type) should be single quoted (e.g. `\"local.ami\"`)\n- In order to provide total parity `jq` functionality, `tq` just shells out to `jq`. We could have probably somehow imported [`gojq`](https://github.com/itchyny/gojq), but did not want to sacrifice functionality for the sake of having a standalone binary when most development environments contain `jq` anyway\n- This project is called `tq` for a reason - it is designed for use with Terraform/OpenTofu files. This is not guaranteed to work with general-purpose HCL files, since Terraform-specific Go libraries are being used under the hood.\n\n## Using as a Go Library\n\n### Example: Build a Terraform file from scratch\n\nSource: [`examples/tf-from-scratch/main.go`](./examples/tf-from-scratch/main.go)\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/jdolitsky/tq/pkg/tq\"\n)\n\nfunc main() {\n\t// Equivalent of:\n\t//\n\t// resource \"aws_instance\" \"app_server_a\" {\n\t//   ami           = local.ami\n\t//   instance_type = \"t2.micro\"\n\t// }\n\t//\n\ttfFile := tq.TerraformFile{\n\t\tBody: tq.TerraformFileBody{\n\t\t\tBlocks: []tq.TerraformFileBlock{\n\t\t\t\t{\n\t\t\t\t\tType: \"resource\",\n\t\t\t\t\tLabels: []string{\n\t\t\t\t\t\t\"aws_instance\",\n\t\t\t\t\t\t\"app_server_a\",\n\t\t\t\t\t},\n\t\t\t\t\tAttributes: map[string]string{\n\t\t\t\t\t\t\"ami\":           \"local.ami\",\n\t\t\t\t\t\t\"instance_type\": `\"t2.micro\"`,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\t// Convert to the hashicorp/hcl data type\n\tfile := tq.Deserialize(\u0026tfFile)\n\n\t// Pretty-print the Terraform\n\tfmt.Println(file)\n}\n```\n\n### Example: Modify an existing Terraform file\n\nSource: [`examples/tf-modify/main.go`](./examples/tf-modify/main.go)\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\n\t\"github.com/jdolitsky/tq/pkg/tq\"\n)\n\nfunc main() {\n\ttfb, err := os.ReadFile(\"./examples/aws.tf\")\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\n\ttfFile, err := tq.ParseTerraform(tfb)\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\n\t// For all \"aws_instance\" resources,\n\t// modify the instance_type to \"t2.large\"\n\tfor _, block := range tfFile.Body.Blocks {\n\t\tif block.Type == \"resource\" {\n\t\t\tif len(block.Labels) \u003e 0 \u0026\u0026 block.Labels[0] == \"aws_instance\" {\n\t\t\t\tblock.Attributes[\"instance_type\"] = `\"t2.large\"`\n\t\t\t}\n\t\t}\n\t}\n\n\t// Convert back to Terraform\n\tfile := tq.Deserialize(tfFile)\n\n\t// Pretty-print the Terraform\n\tfmt.Println(file)\n}\n```\n\n## Alternatives\n\nThis project was only created since there did not appear to be\na reliable way to convert bidirectionally between Terraform to JSON.\n\nThe following alternatives were considered prior to `tq` being made:\n\n- [`hcldec`](https://github.com/hashicorp/hcl/tree/main/cmd/hcldec): This is extremely powerful as it is closely tied into the rest of the Terraform codebase. However, it relies on a pre-existing spec file. This does not work if you want to operate dynamically on any .tf file. You can only also only convert in one direction using the CLI (Go libraries can be used to convert from JSON to Terraform if you have a spec file)\n- [`hcl2json`](https://github.com/tmccombs/hcl2json): This is a third-party tool which will convert any HCL file to JSON. The JSON format is nice and readable (and could be easily piped into `jq`), but it does not provide any way to reliably convert the JSON back to .tf\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjdolitsky%2Ftq","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjdolitsky%2Ftq","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjdolitsky%2Ftq/lists"}