<?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: David Gamez</title>
    <description>The latest articles on DEV Community by David Gamez (@davidgamez).</description>
    <link>https://dev.to/davidgamez</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%2F1293743%2F39d387c1-3d91-4bed-a444-456939762fb3.jpeg</url>
      <title>DEV Community: David Gamez</title>
      <link>https://dev.to/davidgamez</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/davidgamez"/>
    <language>en</language>
    <item>
      <title>When Murphy Meets Terraform: The Tale of a Simple Guard That Saved My Friday</title>
      <dc:creator>David Gamez</dc:creator>
      <pubDate>Wed, 22 Oct 2025 17:07:26 +0000</pubDate>
      <link>https://dev.to/mobilitydata/when-murphy-meets-terraform-the-tale-of-a-simple-guard-that-saved-my-friday-23gg</link>
      <guid>https://dev.to/mobilitydata/when-murphy-meets-terraform-the-tale-of-a-simple-guard-that-saved-my-friday-23gg</guid>
      <description>&lt;p&gt;This is a story about how simple precautionary measures can save you hours of work and a fair bit of your sanity.&lt;/p&gt;

&lt;h2&gt;
  
  
  Context
&lt;/h2&gt;

&lt;p&gt;At &lt;strong&gt;&lt;a href="https://mobilitydata.org/" rel="noopener noreferrer"&gt;MobilityData&lt;/a&gt;&lt;/strong&gt;, we created the &lt;a href="https://mobilitydatabase.org" rel="noopener noreferrer"&gt;MobilityDatabase&lt;/a&gt; to host public transit and shared mobility feeds.&lt;br&gt;&lt;br&gt;
Our infrastructure lives in &lt;strong&gt;Google Cloud Platform (GCP)&lt;/strong&gt;, and everything is deployed using &lt;strong&gt;Infrastructure as Code (IaC)&lt;/strong&gt; powered by &lt;strong&gt;Hashicorp Terraform&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In theory, Terraform keeps everything tidy and predictable. In practice... well, let's just say Murphy's Law also lives in the cloud.&lt;/p&gt;




&lt;h2&gt;
  
  
  Terraform (in a nutshell)
&lt;/h2&gt;

&lt;p&gt;At a high level, &lt;a href="https://developer.hashicorp.com/terraform" rel="noopener noreferrer"&gt;Terraform&lt;/a&gt; revolves around &lt;strong&gt;three main ingredients&lt;/strong&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Configuration files&lt;/strong&gt; (&lt;code&gt;.tf&lt;/code&gt;): These define &lt;em&gt;what&lt;/em&gt; your infrastructure should look like, which services to create, their properties, and dependencies.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;State file&lt;/strong&gt; (&lt;code&gt;terraform.tfstate&lt;/code&gt;): A JSON file that stores the &lt;em&gt;current reality&lt;/em&gt; of your deployed resources, including IDs, metadata, and versions.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The actual cloud resources&lt;/strong&gt;: The real stuff living in GCP, such as Cloud Run services, Pub/Sub topics, buckets, and databases.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here is the magic: Terraform continuously compares your &lt;strong&gt;configuration&lt;/strong&gt; with your &lt;strong&gt;state file&lt;/strong&gt;, then plans changes needed to align reality with your desired setup.  &lt;/p&gt;

&lt;p&gt;When you run &lt;code&gt;terraform plan&lt;/code&gt;, it says:  &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Hey, your config says there should be a new Cloud Run variable, but the state doesn't know about it. Should I fix that for you?"  &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Then, when you approve (&lt;code&gt;terraform apply&lt;/code&gt;), Terraform talks to the cloud provider APIs to make those updates happen.&lt;/p&gt;

&lt;p&gt;It is a beautiful system until versions get out of sync.&lt;/p&gt;

&lt;p&gt;More about how this works is explained &lt;a href="https://developer.hashicorp.com/terraform/tutorials/cli/apply" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Terraform State: The Single Source of Truth
&lt;/h2&gt;

&lt;p&gt;That humble JSON file, the &lt;strong&gt;state&lt;/strong&gt;, is Terraform's brain.&lt;br&gt;&lt;br&gt;
It knows everything: what you created, how it is configured, and who is responsible for it. Without it, Terraform becomes forgetful and might try to rebuild your infrastructure from scratch.&lt;/p&gt;

&lt;p&gt;Because of that, the state file must be handled like a &lt;strong&gt;sacred artifact&lt;/strong&gt;: secure, backed up, and shared safely among your team. (In our case, it lives in a GCP Storage bucket, because no one wants to accidentally delete production with &lt;code&gt;terraform apply&lt;/code&gt; from their laptop.)&lt;/p&gt;




&lt;h2&gt;
  
  
  Different Clouds, Different Flavours
&lt;/h2&gt;

&lt;p&gt;Terraform is cloud-agnostic. It does not care whether you are deploying to AWS, Azure, GCP, or something more exotic like Cloudflare or GitHub Actions.&lt;br&gt;&lt;br&gt;
Each cloud has its &lt;strong&gt;own Terraform provider&lt;/strong&gt;, which translates Terraform's "desired state" into API calls specific to that platform.&lt;/p&gt;

&lt;p&gt;That flexibility is excellent until provider versions change.&lt;br&gt;&lt;br&gt;
That is when the fun begins.&lt;/p&gt;




&lt;h2&gt;
  
  
  Breaking Changes Actually &lt;em&gt;Break&lt;/em&gt; Stuff
&lt;/h2&gt;

&lt;p&gt;Without going too deep into our setup, we needed to add a new property to one of our &lt;strong&gt;Cloud Run&lt;/strong&gt; services.&lt;br&gt;&lt;br&gt;
The configuration looked simple: "Just one new line, what could go wrong?"  &lt;/p&gt;

&lt;p&gt;Turns out, a lot.&lt;/p&gt;

&lt;p&gt;We discovered that our Terraform provider was &lt;strong&gt;one version behind&lt;/strong&gt;, and the new property looked slightly different in the latest one. "No problem," we thought. "Let's just upgrade the provider."&lt;/p&gt;

&lt;p&gt;Famous last words.&lt;/p&gt;

&lt;p&gt;The moment we tried to deploy, Terraform refused to play along:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Error: Resource instance managed by newer provider version&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This was the "mic drop" moment, on a &lt;strong&gt;Friday&lt;/strong&gt;, of course.&lt;/p&gt;

&lt;p&gt;After diving through GitHub issues, Terraform docs, and consulting my &lt;strong&gt;AI army&lt;/strong&gt;, the top suggestion was terrifyingly simple:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"You can just modify the Terraform state manually."&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Editing the State File (a.k.a. Playing with Fire)
&lt;/h2&gt;

&lt;p&gt;Now, JSON may &lt;em&gt;look&lt;/em&gt; friendly, but manually editing your Terraform state is like performing surgery with a chainsaw.  &lt;/p&gt;

&lt;p&gt;You &lt;em&gt;can&lt;/em&gt; do it, but you really should not.&lt;br&gt;&lt;br&gt;
Even the official docs practically scream in all caps:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"You should not manually change information in your state file to avoid unnecessary drift between your configuration, state, and infrastructure."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And they are right. One wrong edit, and Terraform might decide your entire setup no longer exists and "fix" that by deleting everything.&lt;/p&gt;

&lt;p&gt;So yeah, not exactly my idea of a relaxing Friday morning.&lt;/p&gt;




&lt;h2&gt;
  
  
  Redo My State, Perhaps?
&lt;/h2&gt;

&lt;p&gt;Here is where our &lt;strong&gt;fire extinguisher&lt;/strong&gt; came in.&lt;/p&gt;

&lt;p&gt;When we first set up Terraform, we decided to store our state file in a &lt;strong&gt;GCP bucket&lt;/strong&gt;, and we also turned on &lt;strong&gt;object versioning&lt;/strong&gt; (&lt;a href="https://cloud.google.com/storage/docs/object-versioning" rel="noopener noreferrer"&gt;docs here&lt;/a&gt;).  &lt;/p&gt;

&lt;p&gt;We didn't think much of it at the time; it was more of a "just in case" safety measure. But that small checkbox turned out to be our hero.&lt;/p&gt;

&lt;p&gt;We simply rolled back the state file to the previous version, re-ran &lt;code&gt;terraform apply&lt;/code&gt;, and &lt;em&gt;voila&lt;/em&gt;, everything was back to normal. My Friday was saved. Coffee tasted better again. The weekend was back on track.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Terraform is powerful, but like any tool that touches production, it deserves respect and a few safety nets.  &lt;/p&gt;

&lt;p&gt;So, before you dive into fancy refactors or provider upgrades, make sure you have your &lt;strong&gt;"fire extinguishers"&lt;/strong&gt; in place:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Versioned state file
&lt;/li&gt;
&lt;li&gt;Remote backend&lt;/li&gt;
&lt;li&gt;Provider version pinning
&lt;/li&gt;
&lt;li&gt;And maybe a reminder not to &lt;code&gt;terraform apply&lt;/code&gt; on Fridays
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Because when Murphy shows up, you will want more than luck on your side.  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Happy coding!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;About MobilityData&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://mobilitydata.org/" rel="noopener noreferrer"&gt;MobilityData&lt;/a&gt; is a global non-profit maintaining the development of open data standards that power transit and shared mobility apps worldwide. We support specs like &lt;a href="https://gtfs.org/" rel="noopener noreferrer"&gt;GTFS&lt;/a&gt; and &lt;a href="https://gbfs.org/" rel="noopener noreferrer"&gt;GBFS&lt;/a&gt;, working with agencies, companies, and developers to make mobility data more usable and consistent.&lt;/p&gt;

</description>
      <category>devops</category>
      <category>terraform</category>
      <category>googlecloud</category>
      <category>infrastructureascode</category>
    </item>
  </channel>
</rss>
