> ## Documentation Index
> Fetch the complete documentation index at: https://notes.kodekloud.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Introduction

> Overview of Terraform modules explaining structure usage and best practices for reusable Azure infrastructure including root versus child modules inputs outputs and module composition

Welcome to the lesson on Terraform modules.

As infrastructure grows—especially in Azure environments—Terraform configurations often become repetitive and harder to manage. Terraform modules solve this by grouping related resources into reusable, composable units. This lesson builds both conceptual and practical understanding of modules: what they are, how they’re structured, how to call them, and when to use them.

Learning objectives

* Explain what a Terraform module is and why modules are used.
* Distinguish the root module (your working directory) from child modules called by the root module.
* Describe a module’s typical structure and the roles of `main.tf`, `variables.tf`, and `outputs.tf`.
* Call and consume a module using inputs and outputs.
* Compare configurations with and without modules and reason about trade-offs for reusability, consistency, and maintainability in enterprise Azure deployments.

<Callout icon="lightbulb" color="#1CB2FE">
  A Terraform module is simply a folder containing Terraform configuration files. The root module is the configuration in your current working directory; any other folder referenced with a `module` block is a child (or remote) module.
</Callout>

This overview introduces core concepts with minimal, focused examples to make ideas concrete and actionable.

## Root module vs child modules

* Root module: The Terraform configuration in the directory where you run `terraform init` and `terraform apply`. It can call other modules and orchestrate resources.
* Child module: Any module invoked by the root module using a `module` block. Child modules can be local folders, Git repositories, or modules published to the Terraform Registry.

Example: a root module that calls a child module named `storage`:

```hcl theme={null}
# root/main.tf
module "storage" {
  source       = "./modules/storage"
  storage_name = "mystorageacct"
  location     = "eastus"
}
```

## Typical module structure

Modules are usually organized with a small set of well-known files. Following this convention improves clarity, reuse, and versioning.

Directory layout example:

```text theme={null}
modules/
  storage/
    main.tf
    variables.tf
    outputs.tf
    providers.tf       # optional, for provider configuration
    versions.tf        # optional, for Terraform and provider version constraints
```

Common file responsibilities:

| File                           | Purpose                                                                                             |
| ------------------------------ | --------------------------------------------------------------------------------------------------- |
| `main.tf`                      | Define the module’s resources and primary configuration.                                            |
| `variables.tf`                 | Declare input variables the module accepts and their defaults.                                      |
| `outputs.tf`                   | Expose values from the module to the caller.                                                        |
| `providers.tf` / `versions.tf` | Optional: pin provider/terraform versions and provider requirements (useful for published modules). |

Minimal example variables for a storage module:

```hcl theme={null}
# modules/storage/variables.tf
variable "storage_name" {
  description = "Name of the storage account"
  type        = string
}

variable "location" {
  description = "Azure region"
  type        = string
  default     = "eastus"
}
```

Example module resources:

```hcl theme={null}
# modules/storage/main.tf
resource "azurerm_storage_account" "this" {
  name                     = var.storage_name
  location                 = var.location
  resource_group_name      = azurerm_resource_group.rg.name
  account_tier             = "Standard"
  account_replication_type = "LRS"
}

resource "azurerm_resource_group" "rg" {
  name     = "${var.storage_name}-rg"
  location = var.location
}
```

Example outputs:

```hcl theme={null}
# modules/storage/outputs.tf
output "storage_account_id" {
  description = "The ID of the storage account"
  value       = azurerm_storage_account.this.id
}
```

## Calling and consuming a module

In your root module, use a `module` block to call a child module and map inputs. Then reference module outputs with `module.<NAME>.<OUTPUT>`.

Example root invocation and output consumption:

```hcl theme={null}
# root/main.tf
provider "azurerm" {
  features = {}
}

module "storage" {
  source       = "./modules/storage"
  storage_name = "mystorageacct"
  location     = "eastus"
}

output "storage_id" {
  value = module.storage.storage_account_id
}
```

Common commands to execute from the root module directory:

```bash theme={null}
terraform init
terraform plan
terraform apply
```

## Why use modules?

Modules provide several concrete benefits for teams and enterprise Azure deployments:

| Benefit         | Description                                                                                                |
| --------------- | ---------------------------------------------------------------------------------------------------------- |
| Reusability     | Encapsulate repeatable infrastructure patterns (networking, storage, compute) into callable units.         |
| Consistency     | Enforce standardized configurations and naming conventions across environments and teams.                  |
| Maintainability | Smaller focused modules are easier to test, reason about, and update than one large configuration.         |
| Composition     | Build complex architectures by composing smaller modules, simplifying dependency management and lifecycle. |

Design guidance: aim for small, single-responsibility modules with clear input/output contracts. Use inputs to parameterize behavior and outputs to expose only what callers need.

## Comparing configurations: with vs without modules

| Characteristic       | Without modules                            | With modules                                            |
| -------------------- | ------------------------------------------ | ------------------------------------------------------- |
| Code duplication     | High — repeated blocks across environments | Low — reuse module multiple times with different inputs |
| Consistency          | Harder to enforce                          | Easier to enforce standardized patterns                 |
| Testing & validation | More manual across many files              | Test modules once, reuse confidently                    |
| Onboarding           | New contributors face bigger monoliths     | Easier to understand small focused modules              |
| Complexity           | Single large file can be complex           | Complexity managed via composition                      |

## Best practices and considerations

* Keep modules focused (single responsibility) and parameterized through clear inputs.
* Avoid hardcoding environment-specific values in modules; supply them from the root module or environment variables.
* When publishing modules, include `versions.tf` and clear README documentation.
* Be deliberate about provider configuration: prefer configuring providers in the root module and passing provider aliases to child modules when needed.
* Use remote state or workspaces appropriately to manage state separation between environments.

## Related topics and references

* [Terraform Modules Documentation](https://www.terraform.io/docs/language/modules/index.html)
* [Azure Provider for Terraform](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs)
* [Terraform Registry](https://registry.terraform.io/)
* [Best practices for module design](https://www.terraform.io/docs/language/modules/develop/index.html)

Further exploration

* Structuring module inputs and sensible defaults for flexible reuse.
* Publishing and versioning modules: local vs registry vs Git.
* Provider management and remote state strategies across modules.
* Real-world Azure patterns for enterprise: networking, identity, and security modules.

Now that you understand what Terraform modules are and why they matter, proceed to the hands-on example and step-by-step module build in the next lesson.

<CardGroup>
  <Card title="Watch Video" icon="video" cta="Learn more" href="https://learn.kodekloud.com/user/courses/terraform-on-azure/module/e38de693-04a0-45e9-b67a-9f8d26ac03ee/lesson/4555be4c-7064-4566-bcaa-418117bed43f" />
</CardGroup>
