Configuring Terraform Remote State: S3, GCS, Azure Blob

When infrastructure state is stored in a local file on each engineer's machine, changes conflict, and rollback becomes a risk. We configure Terraform Remote State turnkey: we migrate state to secure storage, set up locking, and separate access. The team works in parallel, and change approval time is reduced many times over.

Our competencies:

Frequently Asked Questions

Latest works

  • Development of a web application for FEEDME
    Development of a web application for FEEDME
    1365
  • Development of an online store for the company FURNORO
    Development of an online store for the company FURNORO
    1330
  • B2B Advance company logo design
    B2B Advance company logo design
    776
  • Development of a web application for Enviok
    Development of a web application for Enviok
    1077
  • AIDER company logo development
    AIDER company logo development
    1022
  • CRM development for Chasseurs
    CRM development for Chasseurs
    1113

Terraform Remote State and a local file: what breaks

State is the mapping between configuration and actual resources: without it, the tool does not know what has already been created and what is yet to be created. While this map sits as a file on one engineer's laptop, infrastructure lives on verbal agreements.

The second person either waits or takes a copy and applies a plan to an outdated picture: resources get recreated, change names, some disappear from state and remain orphaned in the cloud.

State locking does not work at all in this scheme — a local file cannot say "busy," so two simultaneous applies simply overwrite each other. A version conflict surfaces later, when it turns out there is no previous snapshot and nothing to roll back to.

Infrastructure drift accumulates silently: manual changes made in the console are not reconciled with the description, and the next plan tries to "fix" what was a conscious decision by the on-call engineer.

The cost here is not in one error, but in loss of controllability: you cannot prove the environment is reproducible, and you cannot return to the state before a change.

Moving work to Terraform remote state — remote storage with versioning and real locking — removes all three classes of failures at once. We break down how this is addressed.

What moving state out gives: parallel work and rollbacks

Local state ties infrastructure to one engineer's machine: the second run overwrites the first one's result, and the discrepancy is exposed in production.

Moving Terraform state to external storage with versioning and locks removes the very possibility of such overwriting — several people and automated runs work on one configuration in parallel.

Parallel work without blocking each other

Storage holds a lock during the operation: while one person applies changes, the others get an explicit rejection instead of a silent write to the same file.

Each manages their own module or environment, but everyone reads one consistent state — discrepancies between environments do not accumulate.

Hence a measurable effect: several engineers and pipelines work simultaneously, without manual file merges and without a "first-come" queue.

Predictable environment recovery

State is an exact list of what is deployed, so during a failure there is no need to reconstruct the picture from logs and team memory. Storage versioning allows returning to a previous state point and repeating the apply — recovery time is cut from hours to minutes.

This also removes a whole class of failures: desynchronization between actual infrastructure and configuration, because of which the next run breaks what already works. Incident analysis relies on state change history — you can see which change and when caused the failure.

State storage options: cloud, own server, local

The Terraform state file is the single source of truth about which resources have already been created. Its storage location determines whether two engineers can apply changes simultaneously without overwriting each other, and whether a path back to a previous revision remains.

Selection criteria for your environment

Option When it fits Limitations
Cloud storage Distributed team, multiple environments, need locking and versioning Requires access rights, encryption, and lifecycle policy setup
Storage in your own environment Regulator requires keeping data inside the perimeter Fault tolerance, backups, and locking are configured by us
Local file Personal stand, one-off experiment No shared locks and history; losing the file means losing resource tracking
Manual file transfer One-time migration or incident analysis State diverges, no protection from simultaneous writes

Where the options do not fit

A local file and manual transfer are incompatible with a distributed team: parallel applies cause a state conflict, and resolving the conflict requires manual reconciliation of every resource.

Cloud storage is out where the regulator prohibits moving data outside the perimeter — then you choose your own environment and separately address locking and backups.

How implementation goes: from audit to handover to the team

Implementation starts with inventory, not with storage setup. We collect a map of environments and a list of machines with access to Terraform state, and separately mark places where it resides outside shared storage — in a repository, on an engineer's disk, on a local server. These points show where a simultaneous write or file loss halts several teams at once.

  1. Infrastructure audit. Record where state is stored, who has access to it, and what locks currently apply. Output: a map of risks and failure points.
  2. Environment separation scheme. Define environment boundaries and a separate state address for each so a training environment cannot modify production.
  3. Storage setup. Deploy object storage with versioning, encryption, and an access log, and configure it for all projects.
  4. State migration. Migrate data without recreating resources, verify object composition before and after so duplicates and lost services do not appear.
  5. Lock and permission verification. Run apply from two machines simultaneously and make sure the second gets a rejection rather than writing over.
  6. Hand over the procedure. Provide documentation, a role matrix, key rotation procedure, and emergency scenario walkthrough.

Testing on a copy of the production environment

Before switching, we deploy a copy of one environment on separate storage and run the full cycle: read, write, rollback to a previous state version. Permission errors and lock conflicts are caught here, not at release time.

Switching procedure without stopping work

Switching goes in waves: first development environments, then intermediate environments, then production. The old storage remains read-only until the end of validation, so rollback takes minutes and does not require stopping releases.

Configurations, access policies, and schemes in the project

Documentation is part of the deliverable, not a byproduct. After handover, the customer's team has a set of descriptions by which a new engineer reproduces the state storage and does not break working environments.

Each item is tied to a specific file or setting in the repository — no discrepancies remain between "as written" and "as deployed."

Access policies and roles

  • Storage structure: placement, environment prefixes, encryption, and object versioning.
  • Environment separation: separate states and accounts for development, staging, and production — test changes do not affect production.
  • Access policies and roles: who reads state, who writes, who only has plan without apply; least privilege principle.
  • Locking rules: state capture on parallel run, timeouts, and the procedure for manually removing a stuck lock.
  • Change flow scheme: from branch and merge request check to apply, with manual confirmation points.

State recovery procedure

  • Procedure for rollback to a previous object version, integrity check after recovery, reconciliation with the change log.
  • Instructions for engineers: typical failures — lost lock, simultaneous apply conflict, deleted resource — and steps for each case.

With such a set, the customer's team does not depend on a specific engineer: daily operations and recovery are performed according to the description, not from memory.

Case: the team stopped blocking changes

A team of eight engineers managed several product environments and stands, and the state file lay locally in a repository and was synced manually.

While releases went one at a time, the scheme held; when three tracks ran in parallel, changes queued — applying fixes waited several hours because the lock was resolved in chat.

Terraform with such state handling gives no guarantees: a diverging file produced false plans and repeated apply of what was already done.

What we did and what the result was

We moved Terraform remote state to object storage and separated environments by distinct keys — production, stands, and sandbox no longer intersect.

We enabled locking during apply, object versioning, and a version retention policy, granted access through service accounts, and disabled manual editing on the storage side.

The apply queue dropped from hours of waiting to minutes: engineers no longer waited for lock release.

Rollback takes 3-5 minutes — returning to a previous object version instead of manually assembling state from backups, which previously consumed up to an hour during the peak of an incident. Incidents due to diverging state were 5-6 per quarter, and became zero to one.

A new environment comes up from the same description in 15 minutes, with the same locking, permissions, and version storage — a repeatable result instead of one-off setup. Side effect: the plan matches the apply, and conflicts are caught by the lock, not in a meeting.

What to do if state already lies locally with every engineer?

Local state almost always diverges: each engineer has their own copy of the resource map, while the real infrastructure is one and already running.

You cannot stop it to restore order, so migration is done on the fly and in two steps — first a reference state is chosen, then the whole team is brought to it.

The reference state is chosen not by the last modification date but by matching reality: the suitable copy is the one that produces an empty plan against actual resources.

The check is simple — run the plan in read-only mode with refresh: everything the plan intends to recreate goes into the import list, not the deletion queue.

Version reconciliation goes per resource: what exists in infrastructure but is absent from the reference map is imported; extra records are removed from the map, not from infrastructure.

As soon as the plan becomes empty, the state file is moved to remote storage with versioning and locking — Terraform then reads and writes only there.

Switching is done in a short window when only one engineer can write to state, while others work in read-only mode; migration is performed by the standard migration command, not by manually copying files.

Local copies are then frozen, removed from the repository, and prohibited by rules — otherwise divergence returns with the first commit.

As a result, any run sees one resource map, locking prevents two people from changing the same thing simultaneously, and the storage's version history allows rolling state back to a previous snapshot. Running infrastructure is not stopped: the storage method changes, not the resources themselves.

Concerns about access, locking, and data migration

Failures with terraform remote state are more often related not to storage, but to the access order for the state file: it is the single source of truth about created resources, and parallel writing breaks deployment predictability. We answer the objections that arise in almost every project.

What happens if two engineers run changes simultaneously?

The second run will get a lock and stop with a clear error — the file will not be overwritten. Locking is enabled by a separate table or conditional write; in a pipeline, runs for one environment are queued.

Can state be migrated without downtime?

Copy the file to the target storage, enable versioning and locking, switch the storage in the configuration, and verify the plan — it should be empty. The old file is decommissioned only after that.

Cloud storage or a dedicated server?

Object storage with versioning solves the task without administration. A dedicated server is justified if data must remain in your own environment: then backup and disk loss protection are added.

Who can overwrite state?

Permissions are assigned by roles: developers — read and lock, write — only for the deployment pipeline. Versioning stores every revision, so manual replacement is visible in history.

What to do after state corruption?

Restore the previous object revision and verify the plan. Resolve discrepancies by importing resources, not by recreating them. Write access during recovery is kept only for the pipeline.

Let's discuss the task and return with an estimate and plan

To discuss the task concretely rather than in general terms, it is useful to attach several inputs to the request — from them we immediately see the environment and do not waste time on clarifying rounds. Drafts, console exports, and notes on "how it is currently done" are enough for this.

  • environment diagram: how many environments, how they are connected, and where the boundary lies between them;
  • the current way of storing Terraform remote state: local file, shared bucket, or manual transfer between engineers;
  • how many engineers and teams work with infrastructure simultaneously;
  • environment constraints: closed perimeter, own access rules, requirements for change logging;
  • how state locking currently works and what happens during a parallel run;
  • the composition of resources already described by code, and what is still managed manually;
  • the desired start order: migration of an existing environment or deployment of a new one.

In response we will return an estimate and plan: a breakdown by stages — inventory, storage preparation, state migration, lock and access setup, rollback testing on a copy — scope of work with responsibility zones, and a list of what will be needed from your side. Then we will agree on the start order and the points at which we show intermediate results.