DriversRecommendedOutdated drivers can make a good PC feel brokenScan driver issues before chasing fixes manually.Scan NowOctober DealsAmazon USOctober deal check: compare before you payAmazon US: current deals, useful picks and tech finds.Check DealsPC HealthRecommendedCrashes, freezes, slowdowns? Check your PC nowSpot repairable issues before they interrupt work.Check PC×
Skip to content
World desk8 min

Infrastructure as Code Best Practices: Terraform State Management, Modular Cloud, and Automated Drift Detection

Terraform best practices for remote state with locking, protecting state and plan files, module boundaries, version pinning, reviewed plans, and investigating drift with refresh-only plans.
Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Sound Terraform practice comes down to one operating model: configuration is versioned and reviewed, state is shared and protected, modules have clear interfaces, provider and module upgrades are deliberate, every plan is read before anything changes, and drift is resolved either by updating the code or by correcting the infrastructure through a reviewed plan. The guidance below follows that model and draws on HashiCorp’s Terraform documentation and Google Cloud’s guidance for Terraform root modules. Where a behavior depends on the backend, the Terraform version, or the HCP Terraform edition, the article says so.

Store state remotely, with locking and recovery

Terraform state records the mapping between your configuration and the real objects it manages, and Terraform reads that record when it builds a plan. A state file on one laptop works until a second person or a CI job needs to run Terraform against the same stack. HashiCorp’s State documentation addresses this directly: “Remote state is the recommended solution to this problem.” The problem in that sentence is everyone working with the same state, so the recommendation is about shared, controlled access, not merely about where the file lives.

As an Amazon Associate I earn from qualifying purchases.

HCP Terraform is HashiCorp’s managed option for centralized collaboration. Self-managed remote backends, including S3, Azure Blob Storage, Google Cloud Storage, and Consul, are valid alternatives. They do not all offer the same controls, so compare them on the same criteria before you commit a stack to one.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Compare backends on the criteria that matter

Criterion What to verify Why it matters
Locking behavior and compatibility Whether the backend locks state during writes, and which Terraform versions support its locking method Overlapping writes can corrupt state or silently drop a change
Encryption and key control Encryption at rest, who controls the keys, and whether keys can be rotated State can hold credentials and other sensitive attributes
Access controls and auditability Who can read or write state, and whether those accesses are logged Read access to state can expose more than read access to code
Recovery and versioning Whether earlier state versions are retained and how one is restored A bad write or an accidental deletion must be recoverable
Operational ownership Who patches, backs up, and responds when the backend fails Ownership determines how quickly an incident is handled
Integration with existing cloud and CI Whether your identity provider and pipeline can authenticate to the backend without stored long-lived secrets Fewer long-lived credentials means fewer to leak or rotate

S3 as a worked example

The S3 backend reference shows how backend details change over time. It describes bucket versioning as highly recommended, and it offers S3 lockfiles through the use_lockfile argument. It also marks DynamoDB-based locking as deprecated. A minimal configuration looks like this:

terraform {
  backend "s3" {
    bucket       = "example-terraform-state"
    key          = "network/prod/terraform.tfstate"
    region       = "us-east-1"
    use_lockfile = true
  }
}
  • Enable bucket versioning so an earlier state version can be restored after a bad write.
  • Set use_lockfile = true on Terraform versions that support it. Confirm the minimum version in the S3 backend reference before you rely on it.
  • If a stack still locks with a DynamoDB table, schedule the migration. The current documentation marks that locking method as deprecated.

Also learn what a failed remote write leaves behind. Local recovery behavior depends on the backend, so find out before an incident where a failed write stores state and how to recover from it.

Protect state, plan files, and credentials

State files and saved plan files can contain credentials and other sensitive attributes. Handle them as secrets, not as ordinary build output.

  • Keep terraform.tfstate, its backups, saved plan files, sensitive .tfvars files, and the .terraform directory out of source control.
  • Commit the Terraform configuration, .terraform.lock.hcl, a .gitignore that excludes the files above, and module documentation covering inputs, outputs, and assumptions.
  • Store saved plan artifacts in CI with the same access controls as state, because a plan can expose the same values.

Marking a variable or output as sensitive hides the value from Terraform’s display output. It does not encrypt the value in the state file. Treat the state file as sensitive whether or not any value is marked.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

In CI, supply backend credentials through the platform’s secret store or through dynamic credentials. Do not place secrets in backend configuration values, because Terraform persists those values in local files.

Structure modules around responsibility and environment

A module boundary should follow one coherent responsibility, not a directory habit. A reusable module works when a consumer can see what it needs, what it produces, and which provider versions it supports.

Root modules are stacks; child modules are patterns

Keep each root module focused on one deployable stack or environment. Move reusable infrastructure patterns into child modules, and only when those patterns have a meaningful interface. A module that wraps a single resource adds indirection without a stable abstraction. Skip it unless the wrapper enforces a real organizational standard.

Rank #3

Draw state boundaries around ownership, blast radius, and how often each part changes. One state file for the whole estate means every plan touches everything. Many small states mean more wiring between them, which is the trade-off the next two sections address.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Hard-code shared values, expose environment choices

Google Cloud’s guidance for cloud root modules recommends hard-coding common service-module inputs and requiring environment-specific inputs as variables. The same split works for most stacks:

Value type Where it belongs Examples
Shared across all deployments Hard-coded in the module, or set as an internal default Naming conventions, standard tags, logging settings
Varies by environment Required root-level input variable Region, instance size, CIDR range, account identifier
Owned by another stack Remote state output or a provider-specific data source Network identifiers owned by a platform team

Share data between stacks deliberately

Remote state can expose root module outputs to other stacks, but it creates a dependency. The consuming stack must be able to read the producing stack’s state, which is an access relationship between two state owners. Where a provider or service data source can look up the value, prefer it. That approach avoids granting read access to another stack’s entire state.

Pin versions and review dependency changes

Most surprise plans come from upgrades nobody reviewed. Pin what can change, commit what was selected, and upgrade on purpose.

Declare Terraform and provider constraints

  • Declare the Terraform core versions each configuration supports, so the supported range is explicit.
  • Reusable modules should state the minimum versions they need. Root modules can set bounded provider version constraints to control when upgrades arrive.
  • Specify provider sources explicitly rather than relying on defaults.

Commit the provider lock file

Running terraform init generates .terraform.lock.hcl. Commit it with the configuration so later runs select the same provider builds. Review changes to the lock file in the same pull request as the configuration change that caused them.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

External modules are not in the lock file

The provider lock file tracks providers only. Terraform does not record remote module selections there, so an external module can change underneath you. Pin remote module versions exactly, or set a narrow range that your team manages on purpose.

Upgrade in isolation

Run provider and module upgrades as their own change, and read the full plan before merging. If an upgrade is mixed with an infrastructure change, it becomes hard to tell which one produced a given diff.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Build a reviewed plan pipeline

A pull-request pipeline makes review the default and keeps applies behind controls. The sequence below is a model. The exact commands, approval gates, and credential handling depend on your Terraform version, backend, and CI platform.

  1. Run formatting and validation checks on every change.
  2. Initialize using the committed lock file and the backend configuration.
  3. Produce a plan against the intended state or workspace, and save it as an artifact.
  4. Expose the plan to reviewers, and require human approval before anything is applied.
  5. Apply only the plan that was reviewed, under your team’s approval controls.
  6. Add policy checks where the organization needs hard limits, such as blocked resource types or disallowed regions.

Detect drift and decide what to do about it

Drift is any difference between what Terraform’s state and configuration describe and what exists in the cloud, usually because someone changed a resource in the console, through a script, or with another tool. Terraform refreshes resource attributes during ordinary plan and apply operations. The harder question is how to investigate drift without changing anything by accident.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Investigate with a refresh-only plan

  1. Change into the directory for the stack in question, run terraform init, and confirm you are using the intended state. If you use workspaces, check the active one with terraform workspace show.
  2. Run terraform plan -refresh-only. Terraform reads the live resources and shows the state updates it would record.
  3. Review every proposed state change. Each one is an attribute whose live value differs from what Terraform last recorded.
  4. Decide which description should be authoritative, using the table below.
  5. Verify with a normal terraform plan. The expected result is no changes, or only the changes you intend.

HashiCorp’s Terraform documentation for resource drift sets the boundary clearly: “A refresh-only operation does not attempt to modify your infrastructure to match your Terraform configuration — it only gives you the option to review and track the drift in your state file.” If you accept the refresh-only result with terraform apply -refresh-only, Terraform records the observed values in state. Infrastructure is still not changed.

Choose which description wins

Situation Action How to verify
The external change was intended Update the configuration so it captures the change A normal plan shows no changes
The change was accidental or unauthorized Run a normal plan that restores the declared configuration, and review what it modifies or replaces The plan shows only the restoration you expect. Some corrections are disruptive or hard to reverse, so check them against the resource’s behavior before applying.
A real resource exists but Terraform does not manage it Bring it under management with an import workflow The plan does not propose creating a duplicate of that resource
The change must stay outside Terraform Record a documented exception with an owner and a review date The exception is listed and reviewed on schedule

Choose a drift-check approach

Approach Changes state or infrastructure? Requirements Best suited to
On-demand refresh-only plan (Terraform CLI) The plan changes neither. Accepting it with terraform apply -refresh-only updates state only. Backend access to the stack Investigating a specific suspected change
HCP Terraform scheduled health assessment Non-actionable. Runs refresh-only plans and does not change state or infrastructure, per HashiCorp’s drift-detection tutorial. An HCP Terraform workspace. The tutorial lists drift detection as a Standard Edition feature, so confirm your edition includes it before building a process around it. Recurring checks across managed workspaces
Third-party continuous discovery and remediation Not stated in Terraform’s documentation Depends on the product Teams that want continuous monitoring beyond what the Terraform-native options provide

Third-party tools fall outside the official guidance covered here, so judge any of them by the same questions. Can it run in a refresh-only mode that never applies changes? Does it remediate without review? Where do its findings and its credentials live, given that they may describe sensitive resources?

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Leave a Reply

Your email address will not be published. Required fields are marked *

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

More from the Wire

  1. World desk4 min
    How to Spot an AI Voice Scam Before Sending MoneyDon’t rely on how a caller sounds. Pause, call back through a known number, and verify the emergency with another trusted person before sending money.
  2. Mountain View desk4 min
    Google’s SynthID Detector: How to Check AI-Generated Images, Video and AudioGoogle’s SynthID Detector looks for an embedded watermark in supported images, video and audio. Here is what its results do—and do not—show.
  3. Redmond desk20 min
    How to create a link to File or Folder in Windows 11Windows 11 gives you several ways to point to a file or folder without moving or duplicating it. You can create a desktop shortcut,…
Recommended PC Tool
Recommended PC Tool
Outdated Drivers Are Slowing You DownFree scan - exact matches
Windows Errors? Fix Them Before They SpreadFree repair scan

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.