Você cria recurso na nuvem pelo console, anota em um documento e ninguém atualiza o documento. Seis meses depois, staging diverge do repositório e ninguém sabe o que mudou nem quando. Terraform declara a infra desejada em HCL, guarda o estado real em backend remoto e reconcilia a diferença a cada terraform apply. A documentação do HashiCorp (2025) trata o state file como fonte de verdade do que existe.

Estado remoto e trava de lock

State file contém IDs, endereços e valores sensíveis; ele não entra no Git. Backend S3 com trava em DynamoDB, ou GCS com trava nativa, serializa o apply: dois engenheiros ao mesmo tempo brigam pela trava, não pelo ambiente. Ambientes separam state por prefixo e por conta cloud: dev, staging e produção não compartilham backend. Recurso de banco de produção ganha prevent_destroy; destroy vira mudança que exige remover a proteção em PR separado.

Módulos com dono e versão

Módulo encapsula de 10 a 30 recursos com interface curta de input e output. Kief Morris, em Infrastructure as Code (O'Reilly, 2ª ed., 2021), recomenda módulo por capacidade: rede, banco, serviço de fila. Módulo com 200 inputs vira gargalo de revisão e versão que ninguém ousa subir. Registro interno publica módulo com tag semver; time consumidor fixa versão e sobe por PR, com diff de infra passando pela mesma revisão de código.

Pipeline: plan no PR, apply no merge

Pull request roda terraform plan e publica o diff no comentário da PR. Merge em main roda apply. Sem esse passo, o plano vive só na máquina de quem aplicou e o resto do time revisa fé. Job agendado roda plan e falha quando encontra drift, o que denuncia mudança feita por console ou por outra pipeline. Uso de -target fora de emergência esconde mudança pendente no state; o time evita.

Import e migração de legado

Recurso pré-existente entra no state via terraform import. Bloco moved renomeia endereço de recurso sem destroy-and-recreate. Migração roda aos poucos: rede crítica primeiro, banco depois, camada de aplicação no fim. Cada apply de migração vira PR com diff revisável. Drift que aparece no import revela o tamanho do dívido antes de qualquer mudança de arquitetura.