{"id":8123,"date":"2025-03-04T07:47:23","date_gmt":"2025-03-04T07:47:23","guid":{"rendered":"https:\/\/www.devopsschool.com\/blog\/?p=8123"},"modified":"2025-03-04T07:47:23","modified_gmt":"2025-03-04T07:47:23","slug":"terraform-modules-explained","status":"publish","type":"post","link":"https:\/\/www.devopsschool.com\/blog\/terraform-modules-explained\/","title":{"rendered":"Terraform Tutorials: Module Complete Guide"},"content":{"rendered":"\n<p>A <strong>Terraform module<\/strong> is a collection of configuration files that encapsulate resources used together to achieve a specific outcome. Modules promote reusability, organization, and maintainability in infrastructure as code by allowing you to group related resources and manage them as a single unit.<\/p>\n\n\n\n<p><strong>Understanding the Module Block<\/strong><\/p>\n\n\n\n<p>In Terraform, you define a module block to incorporate the contents of another module into your configuration. This allows you to reuse existing configurations and standardize resource provisioning across your infrastructure.<\/p>\n\n\n\n<p><strong>Syntax of a Module Block<\/strong><\/p>\n\n\n\n<p>A typical module block has the following structure:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\">module <span class=\"hljs-string\">\"&lt;MODULE_NAME&gt;\"<\/span> {\n  source  = <span class=\"hljs-string\">\"&lt;SOURCE&gt;\"<\/span>\n  version = <span class=\"hljs-string\">\"&lt;VERSION&gt;\"<\/span>\n  <span class=\"hljs-comment\"># Additional arguments corresponding to the module's input variables<\/span>\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>\ue206<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>&lt;MODULE_NAME><\/code>: A unique identifier for the module instance within your configuration.<\/li>\n\n\n\n<li><code>&lt;SOURCE><\/code>: Specifies the location of the module&#8217;s source code. This can be a local path, a Git repository, or a Terraform Registry address.<\/li>\n\n\n\n<li><code>&lt;VERSION><\/code>: Defines the version of the module to use, applicable when sourcing modules from registries.<\/li>\n<\/ul>\n\n\n\n<p><strong>Example: Using a Module from the Terraform Registry<\/strong><\/p>\n\n\n\n<p>Suppose you want to deploy an AWS Virtual Private Cloud (VPC) using a community-maintained module from the Terraform Registry. You can define the module block as follows:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-built_in\">module<\/span> <span class=\"hljs-string\">\"vpc\"<\/span> {\n  source  = <span class=\"hljs-string\">\"terraform-aws-modules\/vpc\/aws\"<\/span>\n  version = <span class=\"hljs-string\">\"3.19.0\"<\/span>\n\n  name = <span class=\"hljs-string\">\"my-vpc\"<\/span>\n  cidr = <span class=\"hljs-string\">\"10.0.0.0\/16\"<\/span>\n\n  azs             = &#091;<span class=\"hljs-string\">\"us-west-1a\"<\/span>, <span class=\"hljs-string\">\"us-west-1b\"<\/span>, <span class=\"hljs-string\">\"us-west-1c\"<\/span>]\n  private_subnets = &#091;<span class=\"hljs-string\">\"10.0.1.0\/24\"<\/span>, <span class=\"hljs-string\">\"10.0.2.0\/24\"<\/span>, <span class=\"hljs-string\">\"10.0.3.0\/24\"<\/span>]\n  public_subnets  = &#091;<span class=\"hljs-string\">\"10.0.101.0\/24\"<\/span>, <span class=\"hljs-string\">\"10.0.102.0\/24\"<\/span>, <span class=\"hljs-string\">\"10.0.103.0\/24\"<\/span>]\n\n  enable_nat_gateway = <span class=\"hljs-literal\">true<\/span>\n  tags = {\n    Terraform   = <span class=\"hljs-string\">\"true\"<\/span>\n    Environment = <span class=\"hljs-string\">\"dev\"<\/span>\n  }\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p><\/p>\n\n\n\n<p>In this example:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>source<\/code>: Specifies the module&#8217;s location in the Terraform Registry.<\/li>\n\n\n\n<li><code>version<\/code>: Ensures that Terraform uses version 3.19.0 of the module, maintaining consistency across deployments.<\/li>\n\n\n\n<li>The subsequent arguments (<code>name<\/code>, <code>cidr<\/code>, <code>azs<\/code>, etc.) correspond to the input variables defined by the module, allowing customization of the VPC&#8217;s configuration.<\/li>\n<\/ul>\n\n\n\n<p><strong>Example: Using a Local Module<\/strong><\/p>\n\n\n\n<p>You can also create and reference local modules within your project directory. Assume you have a module that sets up an AWS EC2 instance, located in the <code>modules\/ec2-instance<\/code> directory:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-built_in\">module<\/span> <span class=\"hljs-string\">\"web_server\"<\/span> {\n  source = <span class=\"hljs-string\">\".\/modules\/ec2-instance\"<\/span>\n\n  instance_type = <span class=\"hljs-string\">\"t2.micro\"<\/span>\n  ami_id        = <span class=\"hljs-string\">\"ami-0c55b159cbfafe1f0\"<\/span>\n  subnet_id     = <span class=\"hljs-string\">\"subnet-abc12345\"<\/span>\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>\ue206<\/p>\n\n\n\n<p>Here:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>source<\/code>: Points to the relative path of the local module.<\/li>\n\n\n\n<li>The arguments (<code>instance_type<\/code>, <code>ami_id<\/code>, <code>subnet_id<\/code>) are input variables defined within the <code>ec2-instance<\/code> module, allowing you to customize the EC2 instance&#8217;s properties.\ue206<\/li>\n<\/ul>\n\n\n\n<p><strong>Key Components of a Module<\/strong><\/p>\n\n\n\n<p>A well-structured Terraform module typically includes the following files:\ue206<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>main.tf<\/code>: Contains the primary resource definitions.\ue206<\/li>\n\n\n\n<li><code>variables.tf<\/code>: Declares input variables to parameterize the module.\ue206<\/li>\n\n\n\n<li><code>outputs.tf<\/code>: Defines output values to expose information about the resources.\ue206<\/li>\n\n\n\n<li><code>versions.tf<\/code>: Specifies the required Terraform version and provider constraints.\ue206<\/li>\n\n\n\n<li><code>README.md<\/code>: Provides documentation on the module&#8217;s purpose and usage.\ue206<\/li>\n<\/ul>\n\n\n\n<p><strong>Best Practices for Using Modules<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Encapsulation<\/strong>: Modules should encapsulate their resources, exposing only necessary inputs and outputs.\ue206<\/li>\n\n\n\n<li><strong>Reusability<\/strong>: Design modules to be reusable across different configurations and environments.\ue206<\/li>\n\n\n\n<li><strong>Versioning<\/strong>: Implement version control for modules to manage changes and ensure stability.\ue206<\/li>\n\n\n\n<li><strong>Documentation<\/strong>: Provide clear documentation within the module directory to explain its purpose and usage.\ue206<\/li>\n\n\n\n<li><strong>Consistency<\/strong>: Use consistent naming conventions and file structures across modules.\ue206<\/li>\n<\/ul>\n\n\n\n<p>By effectively utilizing module blocks, you can create modular, reusable, and maintainable infrastructure configurations, enhancing the scalability and manageability of your Terraform projects.<\/p>\n\n\n\n<p>$ tree minimal-module\/<br> .<br> \u251c\u2500\u2500 README.md<br> \u251c\u2500\u2500 main.tf<br> \u251c\u2500\u2500 variables.tf<br> \u251c\u2500\u2500 outputs.tf<\/p>\n\n\n\n<script src=\"https:\/\/gist.github.com\/devops-school\/78620df7ac84787b7e9f20a904d970d3.js\"><\/script>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">resource <span class=\"hljs-string\">\"azurerm_resource_group\"<\/span> <span class=\"hljs-string\">\"example\"<\/span> {\n  name     = <span class=\"hljs-string\">\"my-resources66\"<\/span>\n  location = <span class=\"hljs-string\">\"West Europe\"<\/span>\n}\n\n<span class=\"hljs-built_in\">module<\/span> <span class=\"hljs-string\">\"apache\"<\/span>{\n\tsource              = <span class=\"hljs-string\">\".\/modules\/install_apache\"<\/span>\n}\n\n<span class=\"hljs-built_in\">module<\/span> <span class=\"hljs-string\">\"nginx\"<\/span>{\n\tsource              = <span class=\"hljs-string\">\".\/modules\/install_nginx\"<\/span>\n\tinstances = &#091;<span class=\"hljs-string\">\"${module.web.instance_ids}\"<\/span>]\n}\n\n<span class=\"hljs-built_in\">module<\/span> <span class=\"hljs-string\">\"network\"<\/span> {\n  source              = <span class=\"hljs-string\">\"Azure\/network\/azurerm\"<\/span>\n  resource_group_name = azurerm_resource_group.example.name\n  address_spaces      = &#091;<span class=\"hljs-string\">\"10.0.0.0\/16\"<\/span>, <span class=\"hljs-string\">\"10.2.0.0\/16\"<\/span>]\n  subnet_prefixes     = &#091;<span class=\"hljs-string\">\"10.0.1.0\/24\"<\/span>, <span class=\"hljs-string\">\"10.0.2.0\/24\"<\/span>, <span class=\"hljs-string\">\"10.0.3.0\/24\"<\/span>]\n  subnet_names        = &#091;<span class=\"hljs-string\">\"subnet1\"<\/span>, <span class=\"hljs-string\">\"subnet2\"<\/span>, <span class=\"hljs-string\">\"subnet3\"<\/span>]\n\n  subnet_service_endpoints = {\n    <span class=\"hljs-string\">\"subnet1\"<\/span> : &#091;<span class=\"hljs-string\">\"Microsoft.Sql\"<\/span>], \n    <span class=\"hljs-string\">\"subnet2\"<\/span> : &#091;<span class=\"hljs-string\">\"Microsoft.Sql\"<\/span>],\n    <span class=\"hljs-string\">\"subnet3\"<\/span> : &#091;<span class=\"hljs-string\">\"Microsoft.Sql\"<\/span>]\n  }\n\n  tags = {\n    environment = <span class=\"hljs-string\">\"dev\"<\/span>\n    costcenter  = <span class=\"hljs-string\">\"it\"<\/span>\n  }\n\n  depends_on = &#091;azurerm_resource_group.example]\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">key parameters available for a Terraform <code>module<\/code> block<\/h2>\n\n\n\n<p>Certainly! Here&#8217;s a table summarizing the key parameters available for a Terraform <code>module<\/code> block:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Parameter<\/th><th>Description<\/th><th>Required<\/th><th>Example<\/th><\/tr><\/thead><tbody><tr><td><code>source<\/code><\/td><td>Specifies the location of the module&#8217;s source code. This can be a local path, a Git repository, or a Terraform Registry address.<\/td><td>Yes<\/td><td><code>source = \".\/modules\/network\"<\/code> or <code>source = \"terraform-aws-modules\/vpc\/aws\"<\/code><\/td><\/tr><tr><td><code>version<\/code><\/td><td>Defines the version of the module to use, particularly when sourcing modules from registries.<\/td><td>No<\/td><td><code>version = \"3.0.0\"<\/code><\/td><\/tr><tr><td><code>providers<\/code><\/td><td>Overrides the default provider configurations for the module. Useful when you need to specify different provider settings for a particular module.<\/td><td>No<\/td><td><code>providers = { aws = aws.us_east }<\/code><\/td><\/tr><tr><td><code>count<\/code><\/td><td>Creates multiple instances of the module. Allows you to scale resources by specifying the number of instances.<\/td><td>No<\/td><td><code>count = 3<\/code><\/td><\/tr><tr><td><code>for_each<\/code><\/td><td>Creates multiple instances of the module based on a map or set of strings. Provides more control compared to <code>count<\/code>, especially when each instance requires unique configurations.<\/td><td>No<\/td><td><code>for_each = { net1 = \"10.0.0.0\/16\", net2 = \"10.1.0.0\/16\" }<\/code><\/td><\/tr><tr><td><code>depends_on<\/code><\/td><td>Specifies dependencies on other resources or modules. Ensures that the module is provisioned only after certain resources or modules have been created.<\/td><td>No<\/td><td><code>depends_on = [aws_vpc.main]<\/code><\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p>*Note: Input variables are user-defined parameters that allow customization of the module&#8217;s behavior. Each input variable must be defined within the module&#8217;s <code>variables.tf<\/code> file. When calling the module, you provide values for these variables.*\ue206<\/p>\n\n\n\n<p>By utilizing these parameters, you can effectively manage and customize the behavior of your Terraform modules, leading to more modular and maintainable infrastructure configurations.<\/p>\n\n\n\n<script src=\"https:\/\/gist.github.com\/rajeshkumarin\/e53662a88488fb76810e377420cb4a5e.js\"><\/script>\n\n\n\n<h2 class=\"wp-block-heading\">Terraform Module Block Source Arguments Style<\/h2>\n\n\n\n<script src=\"https:\/\/gist.github.com\/rajeshkumarin\/a8fcf5f43f2993d2c588ca46f60bf972.js\"><\/script>\n\n\n\n<div class=\"epyt-gallery\" data-currpage=\"1\" id=\"epyt_gallery_48004\"><figure class=\"wp-block-embed wp-block-embed-youtube is-type-video is-provider-youtube epyt-figure\"><div class=\"wp-block-embed__wrapper\"><iframe loading=\"lazy\"  id=\"_ytid_72200\"  width=\"760\" height=\"427\"  data-origwidth=\"760\" data-origheight=\"427\" src=\"https:\/\/www.youtube.com\/embed\/?enablejsapi=1&autoplay=0&cc_load_policy=0&cc_lang_pref=&iv_load_policy=1&loop=0&rel=1&fs=1&playsinline=0&autohide=2&theme=dark&color=red&controls=1&disablekb=0&\" class=\"__youtube_prefs__  no-lazyload\" title=\"YouTube player\"  data-epytgalleryid=\"epyt_gallery_48004\"  allow=\"fullscreen; accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" referrerpolicy=\"strict-origin-when-cross-origin\" allowfullscreen data-no-lazy=\"1\" data-skipgform_ajax_framebjll=\"\"><\/iframe><\/div><\/figure><div class=\"epyt-gallery-list\"><div>Sorry, there was a YouTube error.<\/div><\/div><\/div>\n","protected":false},"excerpt":{"rendered":"<p>A Terraform module is a collection of configuration files that encapsulate resources used together to achieve a specific outcome. Modules promote reusability, organization, and maintainability in infrastructure&#8230; <\/p>\n","protected":false},"author":1,"featured_media":8145,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_joinchat":[],"footnotes":""},"categories":[5129],"tags":[],"class_list":["post-8123","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-terraform"],"_links":{"self":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/8123","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/comments?post=8123"}],"version-history":[{"count":9,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/8123\/revisions"}],"predecessor-version":[{"id":48685,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/8123\/revisions\/48685"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/media\/8145"}],"wp:attachment":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/media?parent=8123"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/categories?post=8123"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/tags?post=8123"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}