Terraform Modules vs. Resources at Scale

terraform

Terraform configurations are built from two main building blocks: resources and modules. Choosing when to write resources directly versus wrapping them in modules has a big impact on readability, reuse, and how safely you can roll changes out across environments.

In this article, we’ll cover what Terraform resources and modules are, how they differ in practice, and a practical rule of thumb for when to use each.

What is a Terraform module?

A Terraform module is a reusable set of Terraform configuration files that defines how to create and manage a piece of infrastructure. Modules let you package infrastructure logic once and reuse it across environments, regions, and projects.

In practical terms, a module is a folder (local) or a remote source that contains Terraform files (usually *.tf) plus supporting docs. A module typically represents one coherent capability, such as:

  • “An S3 bucket with encryption, versioning, lifecycle rules, and logging”
  • “A complete VPC: subnets, route tables, NAT gateway, security groups”
  • “A Kubernetes cluster with node pools, IAM roles, and add-ons”

Terraform always runs a root module (the configuration in your working directory). Any module blocks you declare in the root module (or in other modules) call child modules. 

What is a Terraform resource?

A Terraform resource is a single block of configuration that maps to one “thing” managed by a provider, such as a VM, database, load balancer, or DNS record. The resource block tells Terraform what to create, update, or delete.

Examples of resources include:

  • an AWS S3 bucket (aws_s3_bucket)
  • a Google Cloud VPC network (google_compute_network)
  • an Azure storage account (azurerm_storage_account)
  • a DNS record (cloudflare_record)

When you run terraform plan or terraform apply, Terraform compares your configuration and state to the real world and proposes or performs changes to reconcile them.

What is the difference between a Terraform module and a resource?

A Terraform resource is the smallest unit of infrastructure change: it maps to a single “thing” managed by a provider. A Terraform module is a packaging and composition layer that groups multiple pieces of infrastructure logic together so they can be reused consistently. 

In real-world Terraform projects, resources optimize for direct control and granularity, while modules optimize for repeatability and standardization, which is why “module vs resource” usually comes down to scale and consistency.

The difference becomes most visible when you manage change across many environments: 

  • With resources, you typically adjust behavior instance by instance, keeping everything explicit at the call site. 
  • With modules, you manage infrastructure via a stable interface (inputs/outputs) and can version that interface, making it easier to roll out consistent defaults (naming, tags, security settings) and updates across multiple stacks. 

The tradeoff is abstraction. Modules can hide details and sometimes require stepping into module internals when troubleshooting.

The table below summarizes the main differences between modules and resources:

Aspect Terraform resource Terraform module
Scope One provider-managed object Reusable bundle of configuration (often many resources)
Best for One-off or highly specific infrastructure Standard patterns you repeat across teams/environments
Reuse Low – copy/paste grows over time High – call the same module with different inputs
Change & rollout Update each instance directly Update the module (and version it) to roll changes consistently
Visibility Very explicit at the call site Details may be inside the module
Governance Conventions enforced manually Defaults/standards encoded once and reused everywhere

When to use which?

When you’re building something for the first time, optimize for clarity and speed: keep it as resources so the configuration stays explicit, easy to review, and simple to debug while requirements are still moving. 

Once the shape of the implementation stabilizes and you’re confident it’s a pattern you’ll want again, you can shift toward modules to improve consistency and reduce long-term maintenance.

As a good rule of thumb, start with resources for something new or truly unique, and promote it to a module once it becomes a repeatable pattern with a stable set of inputs. If you find yourself copy/pasting the same blocks, debating naming/tagging every time, or needing to update the same pattern in multiple places, that’s a strong signal it should be a module.

Terraform also gives you tools to refactor as you go:

  • Use moved blocks (Terraform v1.1+) to rename resources or move them into modules without destroying them.
  • Use configuration-driven import blocks (Terraform v1.5+) to bring existing infrastructure under Terraform management as part of the normal plan/apply cycle. Optionally use terraform plan -generate-config-out=... to generate starter configuration for imported resources.
  • If you need to move objects between state files/workspaces without recreating them, use terraform state mv (e.g., with -state / -state-out for local workflows).

Key points

Resources give you maximum clarity and low-level control. Modules give you repeatability, standardized defaults, and easier rollouts across many environments. Start with resources for new or unique work, then graduate to modules once the pattern is stable and reused.

Terraform is really powerful, but to achieve an end-to-end secure GitOps approach, you need to use a product that can run your Terraform workflows. Spacelift takes managing Terraform to the next level by giving you access to a powerful CI/CD workflow and unlocking features such as:

  • Policies (based on Open Policy Agent)
  • Multi-IaC workflows
  • Self-service infrastructure
  • Integrations with any third-party tools

If you want to learn more about Spacelift, create a free account today or book a demo with one of our engineers.

Note: New versions of Terraform are released under the BUSL license, but everything created before version 1.5.x remains open source. OpenTofu is an open-source version of Terraform that expands on Terraform’s existing concepts and offerings. It is a viable alternative to HashiCorp’s Terraform, being forked from Terraform version 1.5.6.

Manage Terraform better with Spacelift

Build more complex workflows based on Terraform using policy as code, programmatic configuration, context sharing, drift detection, resource visualization and many more.

Learn more

Terraform Modules Cheat Sheet

Grab our ultimate cheat sheet PDF to master
building reusable Terraform modules!

Share your data and download the cheat sheet