terraform init is the command that initializes your working directory all at once: it sets up the backend (where state is stored), resolves and downloads providers (the cloud SDK equivalents), fetches modules, and creates the dependency lock file.
The Associate exam frequently tests flags for reconfiguring the backend and migrating state, provider version constraints, and how to handle the lock file. Designing safe initialization and re-initialization flows is essential in real-world work too.
terraform init reads your configuration files (main.tf and so on), resolves and downloads the required providers and modules, and initializes the backend. The results land in the .terraform directory and in .terraform.lock.hcl (the dependency lock file).
Execution breaks down into four phases: provider resolution, module fetching, backend initialization, and lock file generation/update. Use -upgrade when bumping versions, -reconfigure when rebuilding the backend, and -migrate-state when moving state.
| Phase | What gets created/modified | Key related flags | Notes |
|---|---|---|---|
| Provider resolution | .terraform/providers, .terraform.lock.hcl | -upgrade, -plugin-dir, -lockfile=readonly | Leverage TF_PLUGIN_CACHE_DIR in network-restricted environments |
| Module fetching | .terraform/modules | -upgrade | Module versions can also be pinned via the source ref |
| Backend initialization | Remote connection / lock verification | -backend-config, -reconfigure, -migrate-state | Never hard-code credentials into code |
| Dependency lock update | .terraform.lock.hcl | -lockfile=readonly (suppress updates) | Design CI so the lock file is not rewritten unexpectedly |
Bird's-eye view of init
[main.tf] --parse--> (terraform init)
|---> [.terraform/providers]
|---> [.terraform/modules]
|---> [.terraform.lock.hcl]
\---> [Backend handshake + lock]Minimal initialization example (local backend)
terraform {
required_version = ">= 1.5.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
backend "local" {}
}
provider "aws" {
region = var.region
}
variable "region" {
type = string
default = "ap-northeast-1"
}
# 実行
# terraform initThe backend defines where Terraform stores its state file (tfstate). Team workflows almost always use a remote backend (S3, AzureRM, GCS, etc.) rather than local. S3 typically uses DynamoDB for locking, AzureRM uses Blob leases, and GCS prevents conflicts via object generation — each backend has its own concurrency mechanism.
When switching backends on an existing environment, re-initialize with -reconfigure and pair it with -migrate-state to move existing state safely. Never hard-code credentials or secrets in the backend block — pass them via -backend-config or environment variables.
| Backend type | Storage location | Locking strategy | Operational notes |
|---|---|---|---|
| local | Local file | None | Personal experimentation only; not recommended for team use |
| s3 | S3 bucket + prefix | DynamoDB table | Always design bucket/table permissions and encryption carefully |
| azurerm | Blob Storage container | Blob lease | Inject storage_account_name and similar values via backend-config |
| gcs | GCS bucket | Object generation-based | Match service account permissions and bucket locations carefully |
S3 backend and locking relationship
[Terraform CLI] --read/write--> [S3: tfstate]
| \
|---lock/unlock-----------> [DynamoDB: lock item]
|
\---credentials-----------> [IAM/環境変数/プロファイル]S3 backend configuration and safe re-initialization
# main.tf(資格情報は直書きしない)
terraform {
backend "s3" {}
}
# backend.hcl(例)
bucket = "my-tf-state"
key = "app/terraform.tfstate"
region = "ap-northeast-1"
dynamodb_table = "tf-lock"
encrypt = true
# 既存 local から S3 へ安全に移行(非対話)
terraform init \
-reconfigure \
-migrate-state \
-input=false \
-backend-config=backend.hclProviders are the API clients for each platform. Based on required_providers, terraform init fetches the appropriate binaries from sources like the Terraform Registry, places them under .terraform/providers, and records their hashes in .terraform.lock.hcl.
Version constraints matter both in practice and on the exam. Use the ~> operator to express a compatibility range — tracking minor/patch releases while avoiding major upgrades. In CI, leverage TF_PLUGIN_CACHE_DIR to cut download time.
| Operator | Example | Resolved range | Use case / caveats |
|---|---|---|---|
| = | = 5.6.0 | 5.6.0 only | Full pin; useful for emergency pinning |
| ~> | ~> 5.6.0 | >=5.6.0, <5.7.0 | Auto-track patch releases only |
| ~> | ~> 5.0 | >=5.0.0, <6.0.0 | Pin the major version while tracking minor/patch releases |
| >= | >= 5.5.0 | 5.5.0 or higher | No upper bound — risky; not recommended on the exam |
Provider download and caching
[Terraform CLI] --resolve--> [Terraform Registry]
| |
|--download--> [$HOME/.terraform.d/plugin-cache] (任意)
| |
\------deploy-------------> [.terraform/providers]
\-> [.terraform.lock.hcl]Example: pinning providers and configuring the cache
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
random = {
source = "hashicorp/random"
version = "~> 3.6"
}
}
}
provider "aws" {
region = var.region
}
# ダウンロードキャッシュ(シェル環境)
export TF_PLUGIN_CACHE_DIR="$HOME/.terraform.d/plugin-cache"
mkdir -p "$TF_PLUGIN_CACHE_DIR"
# 初期化(制約内で最新版へ)
terraform init -upgradeWhen reusing the same code across dev/stg/prod, split backend settings and credentials into per-environment files and inject them with -backend-config. Use -reconfigure for changes that require re-initialization, and always pair it with -migrate-state when the state location changes.
In CI, force non-interactive runs with -input=false and prevent unexpected lock file updates with -lockfile=readonly.
| Flag | Primary use | Exam takeaway | Operational notes |
|---|---|---|---|
| -reconfigure | Re-initialize the backend | Ignore existing settings and renegotiate | Combine with -input=false to skip prompts |
| -migrate-state | Migrate state to a new backend | Mandatory for safe migration | There is no dry-run mode — back up state beforehand |
| -backend-config | Inject secrets / environment differences | Avoid hard-coding in code | File path and key=value can be combined |
| -upgrade | Update providers/modules | Selects the newest version within constraints | Review the diff in a PR |
| -lockfile=readonly | Prevent lock file updates | Preserve reproducibility | Make it the CI default to reduce accidents |
Initializing one codebase across multiple environments
[repo]
|-- main.tf
|-- backend-dev.hcl
|-- backend-stg.hcl
|-- backend-prd.hcl
[CLI] --dev--> terraform init -backend-config=backend-dev.hcl
[CLI] --stg--> terraform init -backend-config=backend-stg.hcl
[CLI] --prd--> terraform init -backend-config=backend-prd.hclPer-environment backends and init commands for CI
# backend-stg.hcl
bucket = "my-tf-state-stg"
key = "app/terraform.tfstate"
region = "ap-northeast-1"
dynamodb_table = "tf-lock-stg"
# backend-prd.hcl
bucket = "my-tf-state-prd"
key = "app/terraform.tfstate"
region = "ap-northeast-1"
dynamodb_table = "tf-lock-prd"
# ステージングを初期化(ロックファイルは読み取り専用)
terraform init \
-backend-config=backend-stg.hcl \
-input=false \
-lockfile=readonly
# 本番へ backend 切替と state 移行(CI)
terraform init \
-reconfigure \
-migrate-state \
-backend-config=backend-prd.hcl \
-input=false \
-lockfile=readonlyThe classic problems are forgetting -migrate-state during backend reconfiguration, provider version mismatches, and download failures in network-restricted environments. Don't take error messages at face value — always check three things: the .terraform directory, .terraform.lock.hcl, and the backend configuration.
On the Associate exam, expect questions about which flags safely initialize or re-initialize a project, how to handle the lock file, and how to inject credentials securely.
| Symptom | Message excerpt | Likely cause | Typical fix |
|---|---|---|---|
| plan references a different state after a backend switch | Backend configuration changed | -migrate-state was not run | terraform init -reconfigure -migrate-state |
| Provider resolution failure | Failed to query available provider packages | Version constraints / network | Review constraints, run -upgrade, configure caching |
| Lock contention | Error acquiring the state lock | Another run is holding the lock | Wait, then verify the DynamoDB lock is released (force-unlock is a last resort) |
| You want to refuse lock file updates | attempting to write lock file | Unexpected update in CI | Prevent it with -lockfile=readonly |
Common failure pattern (forgotten backend migration)
[local backend] --(state 残存)--> [開発者PC]
\
X terraform init(-migrate-state なし)
\
--> [S3 backend] --結果: state が分断/競合Commands commonly used for recovery and verification
# backend 再交渉 + state 安全移行
terraform init -reconfigure -migrate-state -backend-config=backend.hcl -input=false
# provider を制約内で再選定
terraform init -upgrade
# 異種プラットフォーム向けにロック事前生成(複数 OS/CPU)
terraform providers lock -platform=linux_amd64 -platform=darwin_amd64
# どうしても壊れたときの最終手段(要注意)
# rm -rf .terraform && terraform initAssociate
問題 1
You are migrating an existing project from a local backend to an S3 backend (with DynamoDB locking). You need to safely move the existing state and run non-interactively in CI. Which command is most appropriate?
正解: A
Backend re-initialization requires -reconfigure, and -migrate-state is needed to safely move existing state to the new backend. -input=false makes the run non-interactive in CI, and -backend-config injects secrets. -upgrade only updates providers/modules and does not meet the migration requirement. terraform state push is not the recommended approach for this kind of migration.
When should I run terraform init?
Run it right after cloning a repository for the first time, whenever you change provider, module, or backend settings or version constraints, and after deleting the .terraform directory. It is a prerequisite for plan/apply.
Should .terraform.lock.hcl be committed to VCS?
Yes — it is recommended for root modules. Committing it pins the provider binary hashes and guarantees reproducible builds. Reusable module repos sometimes exclude it depending on policy, but team root code should commit it as standard practice.
Is it OK to put access keys in the backend block?
No, it is not recommended. Inject credentials and secrets via -backend-config, environment variables, profiles, or OIDC/Federation. The exam expects you to know that hard-coding secrets into Terraform code is wrong.
Practice with certification-focused question sets
無料で問題を解いてみるNicheeLab Editorial Team
NicheeLab editorial team focused on data engineering and cloud certification learning. Content is structured around practical study needs and official exam domains.
HCL Syntax: Terraform's Configuration Language (2026)
HCL2 fundamentals for Terraform — blocks, attributes, expres...
Terraform Authoring & Operations Pro: Complete Guide (2026)
Tactics for the Terraform Pro exam — module authoring, works...
Terraform Providers: Plugin Management Fundamentals (2026)
Provider mechanics — required_providers, versions, mirrors, ...
Terraform Resource Blocks: Declarative Infra Units (2026)
Resource block fundamentals — addresses, references, common ...
Terraform Data Sources: Read-Only External Data (2026)
Data source basics — declaration, refresh behavior, dependen...