<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Ryo TAKAISHI</title>
    <description>The latest articles on DEV Community by Ryo TAKAISHI (@r_takaishi).</description>
    <link>https://dev.to/r_takaishi</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2672984%2Feb3bf73b-f160-4f4c-b1fe-39079b714717.jpg</url>
      <title>DEV Community: Ryo TAKAISHI</title>
      <link>https://dev.to/r_takaishi</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/r_takaishi"/>
    <language>en</language>
    <item>
      <title>tftargets: Extracting Terraform Plan/Apply Target Root Modules from Git Branch Diffs</title>
      <dc:creator>Ryo TAKAISHI</dc:creator>
      <pubDate>Sat, 09 Aug 2025 02:34:05 +0000</pubDate>
      <link>https://dev.to/r_takaishi/tftargets-extracting-terraform-planapply-target-root-modules-from-git-branch-diffs-100</link>
      <guid>https://dev.to/r_takaishi/tftargets-extracting-terraform-planapply-target-root-modules-from-git-branch-diffs-100</guid>
      <description>&lt;p&gt;In Terraform CI/CD, running plan/apply for all modules every time is a waste of time and resources.&lt;br&gt;
For example, if you have dozens of modules, running plan/apply on unchanged modules is inefficient.&lt;/p&gt;

&lt;p&gt;To address this, I created tftargets, a tool that outputs a list of modules requiring plan/apply by comparing changes with a specified Git branch.&lt;/p&gt;

&lt;p&gt;With tftargets, you can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Run plan only for one environment (e.g., production or staging) when modules are separated per environment.&lt;/li&gt;
&lt;li&gt;Run plan for multiple root modules when they depend on a changed module.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  tftargets
&lt;/h2&gt;

&lt;p&gt;tftargets (&lt;a href="https://github.com/takaishi/tftargets" rel="noopener noreferrer"&gt;https://github.com/takaishi/tftargets&lt;/a&gt;) analyzes Git branch diffs to determine, at the module level, whether changes occurred.&lt;br&gt;
It uses terraform-config-inspect (&lt;a href="https://github.com/hashicorp/terraform-config-inspect" rel="noopener noreferrer"&gt;https://github.com/hashicorp/terraform-config-inspect&lt;/a&gt;) internally to understand module dependencies and outputs the directories of changed modules as a JSON array.&lt;/p&gt;

&lt;p&gt;While tools like dorny/paths-filter can define plan/apply targets, dependency management becomes cumbersome as complexity grows.&lt;br&gt;
tftargets automatically analyzes module dependencies and lists only the necessary root modules.&lt;/p&gt;
&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;

&lt;p&gt;tftargets is designed for use in GitHub Actions. You can use it in your workflow as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;takaishi/tftargets@main&lt;/span&gt;
  &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;v0.0.3"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Usage
&lt;/h2&gt;

&lt;p&gt;Suppose you manage your Terraform configuration with the following directory structure.&lt;br&gt;
Environments (staging/production) are separated under env/, and each contains root modules for different purposes.&lt;br&gt;
Root modules call modules under modules/ as needed.&lt;/p&gt;

&lt;p&gt;If both app1 and app2 use the ecs module, and you make changes to the ecs module, you will want to run plan/apply for both app1 and app2.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;terraform/
├── env/
│   ├── staging/
│   │   ├── network/
│   │   ├── storage/
│   │   ├── app1/
│   │   └── app2/
│   └── production/
│       ├── network/
│       ├── storage/
│       ├── app1/
│       └── app2/
└── modules/
    ├── alb/
    ├── ecs/
    ├── network/
    └── storage/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can use tftargets (designed for GitHub Actions, but runnable locally) to list target modules by comparing with github.base_ref:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;tftargets &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--base-branch&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'${{ github.base_ref }}'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--base-dir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'${{ github.workspace }}'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--search-path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'terraform/env'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The output will be a JSON array of root module paths:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"/path/to/github/workspace/terraform/env/staging/app1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/path/to/github/workspace/terraform/env/staging/app2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/path/to/github/workspace/terraform/env/production/app1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/path/to/github/workspace/terraform/env/production/app2"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Extracting only environment names
&lt;/h3&gt;

&lt;p&gt;If you want just the environment names from the tftargets output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$TFTARGETS&lt;/span&gt; | jq &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s1"&gt;'map(split("/")[-2]) | unique | sort'&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"production"&lt;/span&gt;,&lt;span class="s2"&gt;"staging"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can then use a matrix in subsequent jobs to process each environment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;plan&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;needs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;tftargets&lt;/span&gt;
  &lt;span class="na"&gt;strategy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matrix&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ fromJSON(needs.tftargets.outputs.tftargets) }}&lt;/span&gt;
  &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;arm-ubuntu-latest&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Running tftargets in subsequent jobs
&lt;/h3&gt;

&lt;p&gt;Inside a matrix job, run tftargets again to narrow down modules per environment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;tftargets &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--base-branch&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'${{ github.base_ref }}'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--base-dir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'${{ github.workspace }}'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--search-path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'terraform/env/${{ matrix.env }}'&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"/path/to/github/workspace/terraform/env/staging/app1"&lt;/span&gt;, &lt;span class="s2"&gt;"/path/to/github/workspace/terraform/env/staging/app2"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Format the output to generate --queue-include-dir arguments for Terragrunt:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$TFTARGETS&lt;/span&gt; | jq &lt;span class="nt"&gt;-rc&lt;/span&gt; &lt;span class="s1"&gt;'map(split("/")[-1]) | map("--queue-include-dir=" + .) | join(" ")'&lt;/span&gt;
&lt;span class="nt"&gt;--queue-include-dir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;app1 &lt;span class="nt"&gt;--queue-include-dir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;app2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note: Terragrunt (&lt;a href="https://terragrunt.gruntwork.io/" rel="noopener noreferrer"&gt;https://terragrunt.gruntwork.io/&lt;/a&gt;) is a wrapper for Terraform that simplifies managing many modules.&lt;br&gt;
By defining dependencies in .hcl files, Terragrunt ensures modules are applied in the correct order.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;tftargets efficiently lists root modules for plan/apply based on Git branch diffs and Terraform module dependencies.&lt;br&gt;
It helps minimize unnecessary runs in CI/CD pipelines.&lt;/p&gt;

&lt;p&gt;I plan to keep improving and adding features to tftargets. Give it a try and share your feedback.&lt;/p&gt;

</description>
      <category>terraform</category>
    </item>
    <item>
      <title>tfclean: Easily Remove Unused moved/import/removed Blocks in Terraform</title>
      <dc:creator>Ryo TAKAISHI</dc:creator>
      <pubDate>Thu, 23 Jan 2025 09:50:29 +0000</pubDate>
      <link>https://dev.to/r_takaishi/tfclean-easily-remove-unused-movedimportremoved-blocks-in-terraform-2h6j</link>
      <guid>https://dev.to/r_takaishi/tfclean-easily-remove-unused-movedimportremoved-blocks-in-terraform-2h6j</guid>
      <description>&lt;p&gt;Terraform’s &lt;code&gt;moved&lt;/code&gt;, &lt;code&gt;import&lt;/code&gt;, and &lt;code&gt;removed&lt;/code&gt; blocks are quite handy. However, it can be a hassle to remove them after you’ve run apply. In reality, there’s no particular restriction stopping you from just deleting them—it’s just tiresome to open a pull request and remove them manually. Although these blocks aren’t used that frequently, I decided to create a tool called tfclean (&lt;a href="https://github.com/takaishi/tfclean" rel="noopener noreferrer"&gt;https://github.com/takaishi/tfclean&lt;/a&gt;)  to make the removal process easier.&lt;/p&gt;

&lt;p&gt;For example, let’s say we have a .tf file like this, containing one aws_security_group resource along with a moved block, an import block, and a removed block:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_security_group"&lt;/span&gt; &lt;span class="s2"&gt;"example"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"example-security-group"&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Example security group"&lt;/span&gt;

  &lt;span class="nx"&gt;egress&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;from_port&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="nx"&gt;to_port&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="nx"&gt;protocol&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"-1"&lt;/span&gt;
    &lt;span class="nx"&gt;cidr_blocks&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"0.0.0.0/0"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;tags&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"example-security-group"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# removed&lt;/span&gt;

&lt;span class="nx"&gt;removed&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;from&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_security_group&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;example&lt;/span&gt;
  &lt;span class="nx"&gt;lifecycle&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;destroy&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# import&lt;/span&gt;

&lt;span class="nx"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"resource_id"&lt;/span&gt;
  &lt;span class="nx"&gt;to&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hoge&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# moved&lt;/span&gt;

&lt;span class="nx"&gt;moved&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;from&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hoge&lt;/span&gt;
  &lt;span class="nx"&gt;to&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;piyo&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you run tfclean with the command below, it will automatically remove the &lt;code&gt;moved&lt;/code&gt;, &lt;code&gt;import&lt;/code&gt;, and &lt;code&gt;removed&lt;/code&gt; blocks for you:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;./dist/tfclean ./dir/of/tffiles
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After running tfclean, the file is modified as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_security_group"&lt;/span&gt; &lt;span class="s2"&gt;"example"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"example-security-group"&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Example security group"&lt;/span&gt;

  &lt;span class="nx"&gt;egress&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;from_port&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="nx"&gt;to_port&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="nx"&gt;protocol&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"-1"&lt;/span&gt;
    &lt;span class="nx"&gt;cidr_blocks&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"0.0.0.0/0"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;tags&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"example-security-group"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# removed&lt;/span&gt;


&lt;span class="c1"&gt;# import&lt;/span&gt;


&lt;span class="c1"&gt;# moved&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, the blocks that previously had to be removed by hand are automatically removed. To streamline this even further, I’ve automated the process in a GitHub Actions workflow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Run apply.&lt;/li&gt;
&lt;li&gt;Automatically remove the blocks using tfclean.&lt;/li&gt;
&lt;li&gt;Create a pull request for the changes.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now, all I need to do is review the diff for the block removals, check the plan results, approve and merge the pull request. I no longer have to manually touch the code. You can find a sample GitHub Actions workflow in the tfclean repository, so feel free to refer to it.&lt;/p&gt;

&lt;p&gt;By the way, tfclean can also reference the tfstate file to remove only blocks that have already been applied. Technically, that’s more accurate, but since we usually run it after apply anyway, I’m not sure how often that feature is needed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;% AWS_PROFILE=xxxxxxx tfclean --tfstate s3://path/to/tfstate /path/to/tffiles
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Functionally, tfclean is mostly complete, although it might not work perfectly with an import block that uses for_each. If you’re someone who finds it tedious to remove these blocks by hand, I’d love for you to give it a try!&lt;/p&gt;

</description>
      <category>terraform</category>
    </item>
  </channel>
</rss>
