Terraform Tutorial — Creating an S3 Bucket

2 minute read

Let’s create your first real infrastructure with Terraform — an S3 bucket on AWS. We’ll go step by step: write the config, run plan, apply, and verify.


Step 1: Create the Project

$ mkdir terraform-s3-demo && cd terraform-s3-demo

Step 2: Write the Configuration

Create main.tf:

terraform {
  required_version = ">= 1.7.0"

  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }
}

provider "aws" {
  region = "us-east-1"
}

resource "aws_s3_bucket" "demo" {
  bucket = "my-terraform-demo-bucket-2024-unique"

  tags = {
    Name        = "Demo Bucket"
    Environment = "learning"
    ManagedBy   = "terraform"
  }
}

⚠️ Warning: S3 bucket names must be globally unique across all AWS accounts. Replace my-terraform-demo-bucket-2024-unique with your own unique name.


Step 3: Initialize

$ terraform init

Initializing the backend...
Initializing provider plugins...
- Finding hashicorp/aws versions matching "~> 5.0"...
- Installing hashicorp/aws v5.31.0...
- Installed hashicorp/aws v5.31.0 (signed by HashiCorp)

Terraform has been successfully initialized!

Step 4: Plan

$ terraform plan

Terraform will perform the following actions:

  # aws_s3_bucket.demo will be created
  + resource "aws_s3_bucket" "demo" {
      + arn                         = (known after apply)
      + bucket                      = "my-terraform-demo-bucket-2024-unique"
      + bucket_domain_name          = (known after apply)
      + bucket_regional_domain_name = (known after apply)
      + id                          = (known after apply)
      + region                      = (known after apply)
      + tags                        = {
          + "Environment" = "learning"
          + "ManagedBy"   = "terraform"
          + "Name"        = "Demo Bucket"
        }
      + tags_all                    = {
          + "Environment" = "learning"
          + "ManagedBy"   = "terraform"
          + "Name"        = "Demo Bucket"
        }
    }

Plan: 1 to add, 0 to change, 0 to destroy.

The + symbol means Terraform will create this resource. (known after apply) means the value will be computed by AWS.


Step 5: Apply

$ terraform apply

  # aws_s3_bucket.demo will be created
  + resource "aws_s3_bucket" "demo" {
      ...
    }

Plan: 1 to add, 0 to change, 0 to destroy.

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

aws_s3_bucket.demo: Creating...
aws_s3_bucket.demo: Creation complete after 2s [id=my-terraform-demo-bucket-2024-unique]

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

Your S3 bucket now exists in AWS!


Step 6: Verify

Check the state:

$ terraform state list
aws_s3_bucket.demo

$ terraform state show aws_s3_bucket.demo
# Shows all attributes including ARN, region, etc.

Verify in AWS CLI:

$ aws s3 ls | grep terraform-demo
2024-01-15 10:00:00 my-terraform-demo-bucket-2024-unique

Step 7: Update the Resource

Add versioning to the bucket by adding a new resource:

resource "aws_s3_bucket_versioning" "demo" {
  bucket = aws_s3_bucket.demo.id

  versioning_configuration {
    status = "Enabled"
  }
}

Run plan to see the change:

$ terraform plan
  # aws_s3_bucket_versioning.demo will be created
  + resource "aws_s3_bucket_versioning" "demo" {
      ...
    }

Plan: 1 to add, 0 to change, 0 to destroy.

Step 8: Clean Up

When you’re done experimenting, destroy everything:

$ terraform destroy

  # aws_s3_bucket.demo will be destroyed
  - resource "aws_s3_bucket" "demo" {
      ...
    }

Plan: 0 to add, 0 to change, 1 to destroy.

Do you want to perform these actions?
  Enter a value: yes

aws_s3_bucket.demo: Destroying... [id=my-terraform-demo-bucket-2024-unique]
aws_s3_bucket.demo: Destruction complete after 1s

Destroy complete! Resources: 1 destroyed.

What’s Next?

You’ve created, updated, and destroyed your first resource. Next, let’s understand how Terraform figures out the order to create resources — dependencies.


← Resource Block Anatomy Resource Dependencies →