How to create a Terraform module

In this article, we will see how to create reusable modules in Terraform. Modules allow us to avoid code duplication. It means the same code can be used to create resources of the same type. By using modules you do not need to copy-paste your code to create multiple resources of the same type. 

For example, you can put the code inside a Terraform module and reuse that module in the staging and production environments, in this way we will be able to have both environments reuse the same code from the same module instead of writing the code multiple times.

In this article, we will write a module for creating an S3 Bucket as an example.


  1. Basic understanding of Terraform.
  2. Terraform installed on your system.
  3. AWS Account (Create if you don’t have one).
  4. 'access_key' & 'secret_key' of an AWS IAM User. (Click here to learn to create an IAM user with 'access_key' & 'secret_key' on AWS, )

What we will do

  1. Write our own module
  2. Create an S3 bucket using the Terraform Module.
  3. Delete the created resource using Terraform Module.

Write our own Terraform module

Create a dedicated directory where you can have your terraform "" file and a module.

Use the following command to create a directory

mkdir -p modules/aws-s3

Write a Terraform Module

Create a file under modules/aws-s3 and copy paste the following block of code which will be used as a module to create an S3 Bucket.

vim modules/aws-s3/

resource "aws_s3_bucket" "s3_bucket" {
  bucket = var.bucket_name
  acl    = "public-read"
  policy = <<EOF
    "Version": "2012-10-17",
    "Statement": [
            "Sid": "PublicReadGetObject",
            "Effect": "Allow",
            "Principal": "*",
            "Action": [
            "Resource": [
  website {
    index_document = "index.html"
    error_document = "error.html"
   tags = var.tags

Terraform Module Code

Declare the required variable in "modules/aws-s3/". If you want you can specify the default values to the variables. Copy paste the following block of code to create the file.

vim modules/aws-s3/

variable "bucket_name" {
  description = "Name of the s3 bucket. Must be unique."
  type = string

variable "tags" {
  description = "Tags to set on the bucket."
  type = map(string)
  default = {}

Terraform variables

Now, create the "" file which will call the module we defined in the above step. To call a module means to include the contents of that module into the configuration with specific values for its variable. Modules are called from within other modules using module blocks:


provider "aws" {
      region     = "${var.region}"
      access_key = "${var.access_key}"
      secret_key = "${var.secret_key}"

module "website_s3_bucket" {
  source = "./modules/aws-s3"

  bucket_name = "${var.bucket_name}"

  tags = {
    Terraform   = "true"
    Environment = "dev"

Terraform main file

All modules require a source argument. Its value is either the path to a local directory of the module's configuration files, or a remote module source that Terraform should download and use.

The same source address can be specified in multiple module blocks to create multiple copies of the resources defined within, possibly with different variable values.

Create "" which will contain the definition of variables. This will hold the default values which need to be passed to the module along with AWS "access_key" and "secret_key".


variable "access_key" { description = "Access key to AWS console" } variable "secret_key" { description = "Secret key to AWS console" } variable "region" { description = "Region of AWS VPC" } variable "bucket_name" { description = "(Required) Creates a unique bucket name" type = "string" default = "test-bucket-rahul-delete" }

Extend file

Now create "terraform.tfvars" which will hold the AWS User Credentials. The following keys need to be changed with the keys of your IAM user. Before specifying these keys, you need to create them from the AWS Console and do not share these keys with anyone.

vim terraform.tfvars

region = "eu-west-3"
access_key = "AKIAQ6GAIA5XX54GLLNG"
secret_key = "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"

Create an S3 bucket using the Terraform Module

Before you execute the following commands make sure you have configured the valid access_key and secret_key.

The  first command to be used is 'terraform init'. This command downloads and installs plugins for providers used within the configuration. In our case it is AWS. 

 terraform init

The second command to be used is 'terraform plan'. This command is used to see the changes that will take place on the infrastructure.

 terraform plan

'terraform apply' command will create the resources on the AWS mentioned in the file. You will be prompted to provide your input to create the resources.

terraform apply

When you execute the above command, upon successful completion, you can see that 1 new resource has been added and 0 has been destroyed.

You can go to the AWS S3 console to verify if the S3 Bucket is created or not.

Delete the created S3 Bucket using Terraform

If you no longer require a resource you created using the configuration mentioned in the file, You can use the "terraform destroy" command to delete all those resources. Here, the S3 bucket will get deleted upon executing the following command.

terraform destroy


In this article, we saw the steps to write our own module and create an S3 bucket using it.  Now the same module can be used to create multiple S3 Buckets, to do so we just need to change the values of variables and reuse the same module.

Share this page:

6 Comment(s)

Add comment

Please register in our forum first to comment.


By: Tushar Kulkarni

Nice Detailed description!

By: baizid

Great Post. The information you provided is really wonderful. Keep up the good work.

By: Oneteam by Scalefusion

Very well explained.

By: Rajesh

So, do we create 2 files ?

Which folder do i create the second ?

Still not clear on how to create terraform modules

By: Rahul Shivalkar


Yes, we create 2 files.

1st in the module.

2nd contains call to the module.

In this case, we have source = "./modules/aws-s3" in 2nd This can be anywhere, but you would need to then pass the path to source accordingly.


By: Stochastic Parrot

Why is the bucket_name declaration repeated? You have it declared in both root and the module level