Cara membungkus infrastruktur menjadi modul reusable dengan struktur main.tf, variables.tf, dan outputs.tf, lalu mengkonsumsinya dari OpenTofu Registry, repositori Git, atau local path untuk membangun platform yang konsisten di banyak tim dan environment.

Di episode 9 sebelumnya kita membahas state manipulation & import workflows — mengimpor infrastruktur eksisting lewat import block dan tofu import, lalu melakukan refactoring tanpa destroy memakai moved block dan tofu state. Infrastruktur kalian sudah tercatat rapi di state dan bisa dikelola dengan aman. Sekarang muncul pertanyaan berikutnya: bagaimana mencegah setiap tim menulis kode yang sama dari nol?
Tanpa modul, lima tim di perusahaan kalian akan mendeklarasikan VPC, security group, dan database masing-masing dengan cara yang sedikit berbeda. Satu tim membuka port SSH ke publik, tim lain lupa memasang encryption, dan yang paling parah — semuanya tampak "berfungsi" sehingga tidak ada yang menyadari inkonsistensinya sampai terjadi insiden.
Di episode ini kita akan membahas reusable modules & OpenTofu Registry: cara membungkus infrastruktur menjadi modul yang bisa dipakai ulang, struktur file standar main.tf, variables.tf, dan outputs.tf, serta cara mengkonsumsi modul dari OpenTofu Registry, repositori Git, atau local path.
Modul adalah kumpulan resource OpenTofu yang dikemas sebagai satu kesatuan dengan input (variabel) dan output (nilai yang diekspos). Analogi terbaiknya adalah mainan Lego: kalian tidak merakit setiap roda gigi sendiri, melainkan memakai blok yang sudah jadi. Semua "configurasi default yang benar" di-encapsulate di dalam modul, dan konsumen cukup memberi input kecil.
Seluruh konfigurasi yang pernah kita tulis sejauh ini — termasuk modul itu sendiri — sebenarnya adalah root module. Bedanya: modul reusable dipanggil berkali-kali lewat block module, sedangkan root module hanya satu dan menjadi titik masuk eksekusi.
Konvensi standar sebuah modul terdiri dari tiga file: main.tf untuk resource, variables.tf untuk input, dan outputs.tf untuk hasil:
resource "aws_vpc" "main" {
cidr_block = var.cidr_block
tags = var.tags
}
resource "aws_subnet" "public" {
count = length(var.public_subnets)
vpc_id = aws_vpc.main.id
cidr_block = var.public_subnets[count.index]
tags = {
Name = "public-${count.index}"
}
}Perhatikan polanya: variables.tf mendefinisikan kontrak input dengan type, description, dan default; main.tf mengkonsumsinya lewat referensi var.nama; outputs.tf mengekspos nilai yang dibutuhkan pemanggil. Modul yang baik hanya mengekspos output yang benar-benar dibutuhkan, bukan seluruh atribut internal.
Tip
Selalu isi description di setiap variabel dan output — ini bukan dokumen sekunder, melainkan bagian dari antarmuka modul. Konsumen modul akan melihat deskripsi ini saat menjalankan tofu docs atau memakai tooling modul. Setelah modul dipanggil, jangan lupa jalankan tofu init untuk mengunduh dependensinya.
OpenTofu Registry (registry.opentofu.org) adalah rumah publik untuk modul dan provider. Modul komunitas yang populer, seperti terraform-aws-modules/vpc/aws, bisa dipanggil langsung dengan penulisan singkat namespace/nama/provider:
module "vpc" {
source = "registry.opentofu.org/terraform-aws-modules/vpc/aws"
version = "5.0.0"
name = "production"
cidr = "10.0.0.0/16"
azs = ["ap-southeast-1a", "ap-southeast-1b"]
}
module "vpc_staging" {
source = "terraform-aws-modules/vpc/aws"
version = "5.0.0"
name = "staging"
cidr = "10.1.0.0/16"
azs = ["ap-southeast-1a"]
}Dua hal yang perlu diperhatikan. Pertama, source bisa ditulis lengkap dengan host registry, atau singkat — host registry.opentofu.org dipakai secara default. Kedua, dua pemanggilan modul yang sama tidak masalah: setiap blok module menghasilkan instansiasi terpisah, masing-masing dengan inputnya sendiri. Inilah kekuatan "satu definisi, banyak instans".
Warning
Selalu pin version saat memakai modul dari registry. Tanpa versi, satu update modul upstream bisa mengubah seluruh infrastruktur kalian secara tak terduga pada tofu init berikutnya. Untuk lingkungan produksi, kombinasikan dengan lock file agar versi provider dan modul terkunci.
Tidak semua modul pantas dipublikasikan ke registry. OpenTofu mendukung tiga sumber utama:
| Sumber | Contoh source | Kapan Dipakai |
|---|---|---|
| OpenTofu Registry | terraform-aws-modules/vpc/aws | Modul publik, versi terkelola |
| Git repository | git::https://github.com/org/modules.git//vpc?ref=v1.0.0 | Modul privat tim, alur review |
| Local path | ./modules/vpc | Modul internal satu repository |
Sumber Git memakai skema git::URL//subdir?ref=ref — garis miring ganda menunjuk ke direktori di dalam repo, dan ref mengunci ke branch, tag, atau commit tertentu:
module "vpc" {
source = "git::https://github.com/org/modules.git//vpc?ref=v1.0.0"
cidr = "10.0.0.0/16"
subnets = ["10.0.1.0/24"]
}Sementara local path paling cocok saat modul masih berkembang di repository yang sama dengan pemanggilnya — tidak perlu push ke registry untuk setiap perubahan:
module "vpc" {
source = "./modules/vpc"
cidr = "10.2.0.0/16"
subnets = ["10.2.1.0/24"]
}Note
Pindah dari local path ke Git biasanya hanya mengubah source — sisanya tetap. Pola pengembangan yang umum: kembangkan di local path, dorong ke Git setelah stabil, lalu kunci ref ke tag rilis di root module. Ini memberi kontrol penuh tanpa menutup kecepatan iterasi.
description; sediakan README bila perlu.tofu test native yang akan kita bahas di episode berikutnya.Pada episode 10 ini kita membangun fondasi modularitas:
main.tf, variables.tf, dan outputs.tf membentuk kontrak modul yang jelas.source singkat dan version yang di-pin.Dengan modul, kalian bisa membangun platform yang konsisten di banyak tim dan environment. Di episode 11 selanjutnya kita akan membahas Formatting, Linting & Native Testing Framework — merapikan kode dengan tofu fmt, memvalidasi dengan tofu validate, memindai dengan Checkov dan Trivy, lalu menulis pengujian .tftest.hcl memakai tofu test tanpa perlu Terratest. Sampai jumpa!