.tf file or a multi-directory layout for multiple environments, organizing files consistently will make day-to-day operations and long-term maintenance much easier. Below we walk through Terraform block types, recommended filenames, state handling, environment separation patterns, and best practices for secrets and version control.
When authoring Terraform, you declare different block types inside .tf files to describe the infrastructure you want to deploy. Application or infrastructure teams state requirements (for example: an S3 bucket, a VM, or a Kubernetes cluster), and Terraform converts those requirements into configuration blocks.
Common Terraform block types:
variable— declare inputs to the configuration.resource— describe real-world infrastructure objects to create and manage.output— expose values after deployment (for use by people, other configurations, or orchestration).provider— configure the provider plugins (e.g., AWS, GCP, Azure, Kubernetes).
.tf extension in the working directory when you run terraform plan, terraform apply, or other commands, and it merges them into a single configuration at runtime.

- A single large
.tffile becomes brittle and hard to review. - Logical separation improves readability, team ownership, and reuse.
- Terraform treats all
.tffiles in the directory as one configuration, so cross-file references (for example, referencing a resource defined in another file) work automatically.
variables.tf— input variable declarationsnetwork.tf— network-related resources (VPCs, subnets, firewalls)kubernetes.tf— Kubernetes resources or provider configuration for clustersoutputs.tf— outputs to expose information after apply

- Using conventional filenames increases predictability across teams.
- Below is a concise reference you can adopt as a starting point.
| File | Purpose | Example / Notes |
|---|---|---|
main.tf | Primary configuration: networks, clusters, compute resources | Put core resource and module blocks here |
variables.tf | Declare input variables | Use variable "env" {} declarations |
outputs.tf | Expose outputs after apply | Use output "bucket_name" {} blocks |
providers.tf | Provider configuration and provider blocks | Examples: provider "aws" { region = "us-east-1" } |
terraform.tfvars | Assign values to variables (auto-loaded) | Use for non-sensitive environment defaults; Terraform loads this automatically if present |
terraform.tfvars and per-environment tfvars:
- You can create environment-specific files like
prod.tfvarsand pass them with-var-file=prod.tfvars. - Do not store secrets in plaintext in
.tfvarsfiles that are committed to version control.

terraform.tfstate— the current state file recording managed infrastructure.terraform.tfstate.backup— prior state backup created before updates..terraform.lock.hcl— dependency lock file for provider versions..terraform/— directory storing downloaded provider plugins and modules.

Always add
terraform.tfstate, terraform.tfstate.backup, .terraform/, and .terraform.lock.hcl to your repository’s .gitignore. This prevents accidentally committing sensitive or environment-specific data into version control.Do not store secrets (API keys, passwords, private keys) in plaintext inside
.tfvars or Terraform files. Use environment variables, a secret manager (e.g., AWS Secrets Manager, HashiCorp Vault), or remote backends with proper access controls instead.- Most organizations manage multiple environments (for example:
dev,staging,prod) and several projects or components. - Rather than a single monolithic working directory, create a top-level
terraform/folder and separate environments and projects into subdirectories.
repo/terraform/<project>/prod/— containsmain.tf,variables.tf,outputs.tf, and its own state.repo/terraform/<project>/dev/— separate working directory and state for development.- Each subdirectory is an independent Terraform working directory with its own backend configuration and lifecycle.
- Reduced blast radius: operations in
devcannot accidentally modifyprodbecause they use separate state files (local or remote). - Clear boundaries make it easier to adopt reusable modules: extract repeated infrastructure into
modules/and call them from environment working directories.

- Use multiple
.tffiles in a single working directory to organize by concern: variables, resources, outputs, and providers. - Adopt conventional filenames (
main.tf,variables.tf,outputs.tf,providers.tf,terraform.tfvars) for consistency across teams. - Keep each environment or project in its own working directory with separate state to minimize risks.
- Protect state files and lock files via
.gitignoreand prefer remote backends (S3, Azure Storage, Google Cloud Storage, or Terraform Cloud) for collaboration and state locking. - Avoid committing secrets; use environment variables, secret managers, or secure backend integrations.
- Terraform Documentation — Configuration Language
- Terraform Backend Configuration
- Best Practices for Terraform State