All Products
Search
Document Center

Terraform:Configure a module block

Last Updated:Jun 04, 2026

A module block lets you call a Terraform module, pass in input variables, and control deployment behavior through meta-arguments such as count, for_each, providers, and depends_on.

Overview

A Terraform module can come from a local path, a version control system, or the Terraform Registry. Modules accept input variables, return output values, and support a set of meta-arguments that control how instances are created and how dependencies are managed.

In Alibaba Cloud environments, modules help standardize resource configurations, maintain consistency across teams and projects, and accelerate environment provisioning.

Terms

A module is a collection of resources defined in one or more .tf files. Every Terraform configuration has at least one root module — the resources in the working directory. A root module can call other modules, referred to as child modules. The same child module can be called multiple times, either within the same configuration or across different configurations, enabling reuse of resource definitions.

Syntax for calling modules

Use a module block to call a module:

module "vpc" {
  source  = "alibaba/vpc/alicloud"
  version = "1.10.0"

  vpc_name   = "example-vpc"
  cidr_block = "172.16.0.0/16"
}
  • vpc is the local name of the module. Use this name to reference the module elsewhere in your configuration.

  • The block body (enclosed in { }) contains the module's argument configuration.

Module argument types

Arguments at a glance:

Argument

Type

Notes

source

string expression

Required

version

string expression

Registry modules only

count

number

Mutually exclusive with for_each

for_each

map or set of strings

Mutually exclusive with count

providers

map

Pass provider configurations to child modules

depends_on

list of references

Explicit dependency declarations

Required meta-arguments

Two arguments are required or strongly recommended for every module call:

  • source: the location of the module source. Required.

  • version: the module version. Recommended for registry modules.

source

The source argument is required for all module calls. It can point to a local path or a remote module source. Note the following:

  1. The value must be a literal string — not an expression.

  2. Multiple modules can share the same source path, and each call creates an independent set of resources.

  3. After modifying a module, run terraform init to reinitialize.

version

Specify a version constraint when using a registry module:

module "slb" {
  source  = "alibaba/slb/alicloud"
  version = "1.10.0"

  name = "example-slb"
}
  • Version constraints apply only to registry modules.

  • Local path modules do not support version pinning.

  • Terraform selects the latest version that satisfies the constraint.

Meta-arguments

Beyond source and version, Terraform provides four meta-arguments for controlling module behavior.

count

Use count to create multiple identical instances of a module. All instances share the same configuration. Access the current instance's position with count.index.

module "ecs" {
  count  = 3
  source = "./modules/ecs"
}
  • Use cases:

    • Create multiple resource groups with identical configurations.

    • Conditionally create a resource: count = var.enabled ? 1 : 0.

    • Deploy multiple test environments at once.

  • Constraints:

    • The value must be known before Terraform executes the plan.

    • Removing an instance from the middle of the list shifts the indexes of subsequent instances, which can trigger unexpected replacements.

    • Not suitable when instances need different configurations — use for_each instead.

for_each

Use for_each to create multiple instances from a map or set, where each instance can have a distinct configuration. Access the current instance's key and value with each.key and each.value.

module "ecs" {
  for_each = toset(["web", "app", "db"])
  source   = "./modules/ecs"
  name     = each.key
}
  • Use cases:

    • Create resources with different configurations per instance.

    • Create resources from dynamic data sources.

    • Manage resource sets that need stable identifiers.

  • Constraints:

    • The value must be known before Terraform executes the plan.

    • Accepts maps and sets of strings.

    • Prefer for_each over count when instances require unique identifiers — it avoids the index-shifting problem.

providers

Use providers to pass specific provider configurations to a child module, enabling cross-region or cross-account deployments.

module "vpc" {
  source = "./modules/vpc"
  providers = {
    alicloud        = alicloud.hz
    alicloud.backup = alicloud.bj
  }
}
  • Use cases:

    • Deploy resources across multiple regions.

    • Manage resources across multiple accounts.

    • Build disaster recovery architectures.

  • Constraints:

    • If omitted, child modules inherit the parent module's default provider.

    • Provider aliases must be declared in the parent module before passing them to child modules.

    • Verify that all required providers are configured before applying.

depends_on

Use depends_on to declare explicit dependencies between modules, ensuring resources are created and destroyed in the correct order.

module "ecs" {
  source     = "./modules/ecs"
  depends_on = [module.vpc, module.security_group]
}
  • Use cases:

    • Use when implicit dependencies are not sufficient to establish the correct ordering.

    • Use when infrastructure must be deployed in a specific sequence.

    • Use when managing complex resource dependencies.

  • Constraints:

    • Use only when necessary — overuse serializes deployments and slows them down.

    • Avoid circular dependencies.

    • Each dependency extends total deployment time, so keep the dependency graph lean.

Choosing the right meta-argument

  1. Match the argument to the use case

    • count: identical resource groups or conditional creation.

    • for_each: resource sets that need unique, stable identifiers.

    • providers: cross-region or cross-account deployments.

    • depends_on: complex dependencies that Terraform cannot infer automatically.

  2. Consider performance

    • Both count and for_each can affect deployment speed on large resource sets. Prefer for_each for its stable key-based identity.

    • Use depends_on sparingly — each explicit dependency adds sequential wait time to your deployments.

    • Optimize the dependency graph to minimize total deployment time.

  3. Consider maintainability

    • Use descriptive, consistent naming conventions for modules.

    • Document why each dependency exists, especially explicit depends_on declarations.

    • Review and simplify configurations regularly as infrastructure evolves.

FAQ

  1. How do I initialize or update a module? Run terraform init after adding or modifying a module. To upgrade an existing module to the latest allowed version, run terraform init -upgrade.

  2. How do I resolve version conflicts? Check that version constraints in your configuration are compatible. Make sure the entire team pins to the same version, and test compatibility before upgrading.

  3. How do I access resources defined inside a module? Use output values to expose resources from a module. Avoid accessing module internals directly — this breaks encapsulation and makes modules harder to maintain.

  4. What naming conventions should I follow? Use descriptive module names that reflect the resource or role. Keep naming consistent across modules and avoid ambiguous abbreviations.