Quick answer: Terraform is an infrastructure as code tool that defines cloud resources in declarative configuration files, shows a plan of changes and applies them consistently. For small businesses, good Terraform practice means remote state with locking, small reusable modules, separate state per environment, plan-on-pull-request and apply-from-pipeline workflows, and importing existing resources gradually rather than rebuilding everything at once.
Key takeaways
- Store Terraform state remotely with locking and encryption, never on a laptop or in Git.
- Separate state per environment so a mistake in dev cannot affect production.
- Review terraform plan output in pull requests and apply only from a pipeline.
- Bring existing infrastructure under management gradually with import blocks.
- Keep modules small and pin provider and module versions.
Clicking through a cloud portal is fine for experiments. For anything that runs your business, infrastructure should be defined in code, reviewed like code and deployed by automation. Terraform is the most widely used tool for that job across Azure, AWS and Google Cloud. This guide explains how small businesses and nonprofits can adopt it without overengineering. It is part of our DevOps consulting resources.
What is infrastructure as code?
Infrastructure as code (IaC) means describing servers, networks, databases, identities and policies in text files that live in version control. A tool reads those files and makes the real environment match.
Benefits for small teams:
- Repeatability: create identical dev, staging and production environments
- Reviewability: see exactly what will change before it happens
- Recoverability: rebuild an environment after an incident or region outage
- Documentation: the code is an always-current description of your infrastructure
- Auditability: Git history shows who changed what and why
How does Terraform work?
Terraform uses declarative configuration written in HashiCorp Configuration Language (HCL). You describe the desired end state; Terraform compares it to the current state and produces a plan.
The core workflow:
terraform initdownloads providers and configures the backendterraform planshows what will be created, changed or destroyedterraform applymakes the changes after approval- State is updated to record the real resources
Providers are plugins for each platform: azurerm and azapi for Azure, aws for AWS, google for Google Cloud, plus providers for GitHub, Cloudflare, Microsoft Entra ID and many more.
How should Terraform state be managed?
Store state in a remote backend with encryption, locking and tightly restricted access. Local state files are the single most common cause of Terraform problems in small teams.
| Cloud | Common backend | Locking |
|---|---|---|
| Azure | Azure Storage account blob container | Blob lease |
| AWS | Amazon S3 bucket | S3 native locking (or DynamoDB in older setups) |
| Google Cloud | Cloud Storage bucket | Built in |
| Any | HCP Terraform workspace | Built in |
State rules:
- Never commit state files to Git
- Enable versioning on the storage so you can recover from corruption
- Restrict access to the pipeline identity and a few administrators
- Use separate state per environment, and often per major component
- Mark sensitive outputs and avoid writing secrets into state where possible
How should a Terraform repository be structured?
Use a simple structure: environment folders that call a small number of shared modules. Small teams rarely need complex frameworks or dozens of layers.
infra/
modules/
network/
app-service/
database/
envs/
dev/
main.tf
backend.tf
terraform.tfvars
prod/
main.tf
backend.tf
terraform.tfvars
Guidelines:
- Keep modules focused (a network, an app platform, a database), not one giant "everything" module
- Pin Terraform, provider and module versions, and commit the dependency lock file
- Prefer well-maintained registry modules, such as Azure Verified Modules, over writing everything yourself
- Use consistent naming and tagging, aligned with your Azure governance framework or AWS account structure
How should Terraform run in CI/CD?
Run formatting, validation, security checks and plan on every pull request, post the plan for review, and run apply only from the pipeline after approval. Humans should rarely apply from laptops.
A typical workflow:
- Developer changes Terraform on a branch and opens a pull request
- Pipeline runs
terraform fmt -check,validate, a linter such as TFLint and a policy or security scanner such as Checkov or Trivy - Pipeline runs
planand posts a summary to the pull request - Reviewer checks the plan, especially any destroy or replace actions
- After merge, the pipeline applies to dev automatically and to production after an environment approval
Use OpenID Connect workload identity federation so GitHub Actions, Azure Pipelines or GitLab CI can authenticate to the cloud without stored secrets. See CI/CD pipeline best practices for the broader pipeline design.
How do you bring existing infrastructure under Terraform?
Import gradually. Start with low-risk resources, write matching configuration, import them into state and run plan until it shows no changes. Then move to more critical resources.
- Use
importblocks, which can be reviewed in pull requests like other code - Use configuration generation features or tools like Azure Export for Terraform to produce a starting point, then clean up the output
- Avoid importing everything in one change; one resource group or application at a time is manageable
- Lock down portal changes once a resource is managed, or drift will return
What are common Terraform pitfalls?
Most problems come from shared or local state, oversized configurations, unpinned versions and manual changes made outside Terraform.
| Pitfall | Consequence | Fix |
|---|---|---|
| Local state | Lost or conflicting state | Remote backend with locking |
| One state for all environments | Dev mistakes hit production | Separate state per environment |
| Unpinned providers | Surprise breaking changes | Version constraints and lock file |
| Manual portal edits | Drift and confusing plans | Scheduled drift detection, restricted permissions |
| Secrets in variables files | Leaked credentials | Vault references, pipeline secrets |
| Ignoring destroy in plans | Accidental data loss | Plan review, lifecycle prevent_destroy on data stores |
Terraform or Bicep?
Azure-only organizations should consider Bicep, which is Azure-native and stateless from the user's perspective. Multi-cloud teams or those managing SaaS resources often prefer Terraform. Read the full Terraform vs Bicep comparison.
If you are setting up AWS accounts, Terraform pairs well with the patterns in the AWS landing zone guide. For help codifying an existing environment, contact us or start with a free cloud assessment.
How to adopt Terraform in a small business: step-by-step summary
Set up remote state
Create a remote backend such as an Azure Storage account, Amazon S3 bucket, Google Cloud Storage bucket or HCP Terraform workspace, with locking and restricted access.
Structure the repository
Organize configuration into environment folders that call shared modules, and pin Terraform, provider and module versions.
Automate plan and apply
Run terraform fmt, validate and plan on every pull request, and apply approved changes from a CI/CD pipeline using federated credentials.
Import existing resources
Bring existing cloud resources under management with import blocks, starting with low-risk resources, until plans show no unexpected changes.
Detect drift
Run scheduled plans to detect manual changes and reconcile them through code.
Frequently asked questions
Is Terraform free to use?
Terraform's command-line tool can be downloaded and used without a license fee, though HashiCorp moved it to the Business Source License, which restricts some commercial competitive uses rather than typical internal use. OpenTofu is an open-source fork under the Mozilla Public License that is largely compatible. HCP Terraform, HashiCorp's managed service, has free and paid tiers. Check current license terms before building products on top of Terraform.
Should a small business use Terraform or Bicep?
If you run only on Azure, Bicep is a strong option because it is Azure-native, needs no separate state file and supports new Azure features quickly. Terraform is better when you use multiple clouds, manage SaaS tools like GitHub, Cloudflare or Datadog alongside cloud resources, or want one language across providers. Both are good choices with mature tooling.
What is Terraform state and why does it matter?
Terraform state is a file mapping your configuration to real resources, including IDs and attributes. Terraform uses it to calculate what to create, change or destroy. State can contain sensitive values, so it must be stored in a secure remote backend with encryption, access control and locking to prevent two people applying changes at the same time.
Can Terraform manage resources that were created manually?
Yes. Terraform import blocks let you bring existing resources under management by writing matching configuration and importing them into state. Recent Terraform versions can also generate starter configuration for imported resources. Import gradually and run plans until they show no unexpected changes. Tools like Azure Export for Terraform can help produce initial code for existing Azure resources.
Part of the DevOps Consulting hub.