Install Terraform and Build the First Configuration
This lesson turns Terraform from an installed binary into a working mental model. The outcome is simple: install the Terraform CLI, write a small configuration, initialize its provider plugins, preview the action Terraform intends to take, apply the change, inspect the resulting state, and clean it up. Those steps are the foundation for every later Terraform workflow in this course, whether the target is a local file, a cloud network, a Kubernetes namespace, or a complete application platform.
Terraform is an infrastructure as code tool. You describe the desired end state in configuration files, and Terraform compares that desired state with what it knows about real objects. It then proposes actions to close the gap. The first configuration in this lesson uses the local provider because it requires no cloud account and makes Terraform’s behavior visible on your own filesystem. The mechanism is the same when Terraform later calls a cloud API: configuration plus provider schemas plus state produce a plan, and applying the plan updates both the remote object and Terraform’s state record.
How Terraform Works Internally
The Terraform CLI is the front end. It reads files ending in .tf, parses HashiCorp Configuration Language, loads provider plugins, asks those providers what resource types and arguments they support, and builds a dependency graph. A resource block such as local_file.example becomes a node in that graph. References between values, such as one resource using another resource’s attribute, become graph edges. Terraform uses that graph to decide creation, update, read, and deletion order.
Providers are separate executable plugins. The Terraform CLI does not know how to create a file, an S3 bucket, a virtual machine, or a DNS record by itself. Instead, a provider exposes resource types and implements operations for them. During terraform init, Terraform downloads the required provider versions into a local plugin cache for the working directory and records provider selections in .terraform.lock.hcl. That lock file is important because it keeps a team from silently using different provider builds for the same configuration.
State is Terraform’s mapping between resource addresses and real objects. For this first lesson, state is stored in a local file named terraform.tfstate. If Terraform creates local_file.hello, state records the resource address, provider type, selected arguments, and observed attributes. On the next plan, Terraform compares configuration with state and refreshes the object through the provider where possible. If the object differs, Terraform reports drift. If the configuration changes, Terraform reports the actions needed to match the new desired state.
Configuration Anatomy
A minimal Terraform project is a directory containing one or more .tf files. File names are for humans; Terraform loads all files in the directory together. A terraform block configures CLI-level requirements such as required providers. A provider block configures a provider instance when it needs settings. A resource block declares one managed object. The resource type comes first, the local name comes second, and together they form the resource address.
terraform {
required_providers {
local = {
source = "hashicorp/local"
}
}
}
resource "local_file" "hello" {
filename = "hello-terraform.txt"
content = "Hello from Terraform\n"
}
In this example, local_file is the provider’s resource type and hello is the name chosen in this configuration. The address is local_file.hello. The two arguments, filename and content, are interpreted by the local provider. After apply, the deterministic result is a file named hello-terraform.txt containing one line: Hello from Terraform.
Example 1: Install and Confirm the CLI
Install Terraform with the method appropriate for your operating system: a trusted package repository, a package manager, or the official binary distribution. After installation, confirm that your shell can find the binary and that the CLI starts correctly.
terraform version
terraform -help
The exact version output depends on the installed release, so do not build automation around the full string. The important behavior is that terraform version exits successfully and prints a Terraform version line, while terraform -help lists commands such as init, plan, apply, destroy, fmt, and validate. If the command is not found, the binary is not on PATH or installation did not complete.
Example 2: Build a First Local Resource
Create a clean directory and place the earlier configuration in main.tf. Then run the normal Terraform workflow.
terraform init
terraform fmt
terraform validate
terraform plan
terraform apply
terraform init prepares the working directory and installs the local provider. terraform fmt rewrites configuration into Terraform’s standard style. terraform validate checks that the configuration is syntactically valid and internally consistent. terraform plan should show one resource to add. terraform apply asks for approval, then creates the file and records it in state. After apply, ls hello-terraform.txt should show the file, and cat hello-terraform.txt should print Hello from Terraform.
Example 3: Add an Input and an Output
Terraform configurations become reusable when hard-coded values are moved into variables and useful results are exposed as outputs. This version lets the operator choose the message while keeping the filename fixed.
variable "message" {
type = string
description = "Text written into the generated file."
default = "Hello from a variable"
}
resource "local_file" "hello" {
filename = "hello-terraform.txt"
content = "${var.message}\n"
}
output "generated_file" {
value = local_file.hello.filename
}
If you apply this after the first example, Terraform detects that the desired content changed. The plan should show an update or replacement for the managed file, depending on the provider’s schema for the changed argument. After apply, Terraform prints an output named generated_file with the value hello-terraform.txt. Running terraform output generated_file should return the same filename.
Example 4: Create Two Dependent Values
Terraform expressions let one object or value depend on another. The following configuration builds file content from local values, then writes it to disk. The dependency is not a manual step list; it comes from references in the expression graph.
locals {
owner = "platform-team"
purpose = "first-configuration"
body = "owner=${local.owner}\npurpose=${local.purpose}\n"
}
resource "local_file" "metadata" {
filename = "metadata.txt"
content = local.body
}
The deterministic output is a file named metadata.txt with two lines: owner=platform-team and purpose=first-configuration. The important lesson is that Terraform evaluates expressions and builds dependencies before it applies changes. If local.body changes, Terraform knows the file content depends on it and can plan the necessary update.
Design Choices and Trade-offs
Installing Terraform directly on a workstation is convenient for learning and small experiments. Team workflows usually need more control: a pinned CLI version, a committed provider lock file, repeatable automation, and a shared state backend. Local state is easy to inspect but fragile because it lives on one machine and can be edited or deleted accidentally. Remote state adds setup work but supports collaboration, access control, backups, and locking.
The local provider is ideal for learning because it avoids cloud credentials and cost. Its limitation is that it does not teach cloud API latency, quota failures, eventual consistency, or permission boundaries. That is why this course starts with local resources for the mechanism, then moves to providers that manage real infrastructure. The workflow remains the same, but the consequences of a bad plan become larger.
Running terraform apply interactively is useful while learning because the approval prompt forces you to read the plan. In automation, teams usually save a reviewed plan and apply that exact plan in a controlled job. The trade-off is speed versus reviewability: skipping plan review is faster, but it removes the best opportunity to catch accidental replacement or deletion before Terraform changes real objects.
Failure Modes and Troubleshooting
Symptom: terraform prints command not found. Cause: the binary is not installed or its directory is missing from PATH. Diagnose: run which terraform on Unix-like shells or the equivalent command lookup for your shell. Correction: install Terraform from a trusted source, add the install directory to PATH, open a new shell, and rerun terraform version.
Symptom: terraform init fails while installing a provider. Cause: network access, proxy configuration, registry access, or a provider source typo is preventing download. Diagnose: read the provider address in the error and compare it with the required_providers block. Check whether the machine can reach the provider registry through its configured network path. Correction: fix the provider source, configure the proxy, or use an approved provider mirror if your organization requires one.
Symptom: terraform validate reports an unsupported argument or unknown resource type. Cause: the configuration uses an argument not supported by the selected provider schema, or the provider requirement is missing. Diagnose: run terraform init first, then inspect the exact block and argument named in the validation error. Correction: update the configuration to match the provider’s documented schema or add the correct provider requirement.
Symptom: a later plan shows Terraform wants to recreate or change a file that already exists. Cause: the file was changed outside Terraform, or the configuration changed since the last apply. Diagnose: compare the plan diff with the current file contents and with terraform state show local_file.hello. Correction: decide whether Terraform or the manual change is the desired source of truth, then either update configuration or let Terraform restore the configured content.
Security, Performance, and Reliability
Even the first local configuration introduces habits that matter later. State can contain sensitive values, so do not casually commit terraform.tfstate to source control. Provider plugins are executable code, so install them from expected sources and commit .terraform.lock.hcl for reproducibility. Configuration files should be reviewed like application code because they describe actions Terraform may perform against real systems.
Performance is rarely visible in a two-resource local example, but Terraform’s graph model matters as configurations grow. Independent resources can often be processed concurrently, while references force ordering. Reliability depends on keeping the graph understandable, making small changes, reviewing plans, and avoiding manual edits to managed objects unless you intend to reconcile drift afterward.
Hands-on Lab
Prerequisites: Terraform installed, a terminal, permission to create files in an empty working directory, and no need for cloud credentials. Use a disposable directory so cleanup is straightforward.
- Create a directory named
terraform-first-configand enter it. - Create
main.tfusing the first local file configuration from this lesson. - Run
terraform initand confirm that provider installation completes successfully. - Run
terraform fmtandterraform validate. Validation should report that the configuration is valid. - Run
terraform plan. Verify that the plan says one resource will be added and that the address islocal_file.hello. - Run
terraform apply, approve the prompt, and confirm thathello-terraform.txtexists. - Run
terraform state list. It should includelocal_file.hello. - Edit the content string, run
terraform planagain, and observe how Terraform reports the proposed change before applying it.
Verification: the file exists, its content matches the configuration, terraform state list shows the resource address, and a second plan after apply reports no changes if nothing has drifted.
Cleanup: run terraform destroy from the lab directory and approve the prompt. Terraform should remove the managed file and update state. Afterward, remove the disposable directory if you no longer need the exercise files.
Assessment Exercises
- A teammate says Terraform creates resources in the order blocks appear in
main.tf. Use the dependency graph model to explain why that is incomplete and how references affect ordering. - You run
terraform planafter manually editinghello-terraform.txt, and Terraform wants to change it back. Explain what Terraform is comparing and how you would decide the correct fix. - Why is
.terraform.lock.hcluseful even in a small project? Answer in terms of provider selection and repeatability. - Change the variable example so the filename is also an input. What validation would you add to reduce accidental writes to the wrong path?
- Describe when local state is acceptable and when a shared remote backend becomes necessary.
Summary
Installing Terraform is only the first step. The durable skill is understanding the workflow: write desired state, initialize providers, format and validate configuration, review the plan, apply deliberately, inspect state, and clean up managed objects. The local provider keeps the first configuration small, but it exposes the same core ideas used throughout Terraform: provider schemas, resource addresses, dependency graphs, plan diffs, state, drift, and reconciliation.
