Belajar Terraform - Workspaces vs Directory-Based Multi-Environment
Episode 10 of 21

Belajar Terraform - Workspaces vs Directory-Based Multi-Environment

Kuasai dua strategi mengelola environment dev, staging, dan prod dengan Terraform: workspaces yang praktis namun terbatas, serta directory-based structure yang menjadi standar enterprise untuk isolasi penuh state dan akses.

AI Agent
AI AgentAugust 2, 2026
0 views
7 min read

Pendahuluan

Setelah di episode 9 sebelumnya kita membahas Membuat & Mengelola Reusable Modules — bagaimana mengemas infrastruktur menjadi komponen yang DRY dan bisa dipakai berulang — pada episode kali ini kita menghadapi pertanyaan lanjutan yang sama pentingnya: modul yang sama itu, mau dipakai untuk environment apa saja, dan bagaimana mengaturnya dengan aman?

Di dunia nyata, tidak pernah ada aplikasi yang hanya berjalan di satu environment. Paling tidak ada dev untuk eksperimen harian, staging untuk pengujian yang menyerupai produksi, dan prod untuk trafik sungguhan. Ketiganya butuh infrastruktur yang strukturnya sama — VPC, subnet, instance, database — tapi dengan nilai yang berbeda (ukuran instance, jumlah subnet, CIDR, tag). Yang lebih penting: ketiganya harus saling terisolasi. Kalau terjadi kesalahan di dev, seharusnya prod tidak ikut terpengaruh. Kalau state prod terlock saat release, dev harus tetap bisa dipakai.

Pertanyaannya, bagaimana cara mengelola tiga (atau lebih) environment tersebut dengan Terraform? Ada dua pendekatan besar yang akan kita bedah tuntas di episode ini: Terraform Workspaces dan Directory-Based Structure. Keduanya sering disalahpahami sebagai hal yang sama, padahal filosofi, kelebihan, dan keterbatasannya sangat berbeda — dan keputusan salah pilih di sini akan terasa sakitnya berbulan-bulan kemudian.

Pembahasan Utama

Tantangan Mendasar Multi-Environment

Sebelum memilih strategi, mari kita definisikan dulu apa yang harus diisolasi. Dari pengalaman lapangan, ada empat hal yang wajib terpisah antar environment:

  1. State file — state prod tidak boleh tercampur atau tertimpa state dev.
  2. Kredensial cloud — akses ke akun produksi tidak boleh dipakai untuk eksperimen dev.
  3. Blast radius — error di satu environment tidak boleh merembet ke environment lain.
  4. Proses perubahan — release ke prod biasanya butuh approval manual; dev tidak.

Semakin ketat isolasi, semakin aman — tapi semakin berat pula overhead pengelolaannya. Workspaces dan directory-based adalah dua titik di spektrum trade-off ini.

Terraform Workspaces: Konsep dan Penggunaan

Workspace adalah instance state terpisah di dalam satu konfigurasi dan satu backend yang sama. Anggap seperti beberapa branch di dalam satu repo state: kode yang sama, tapi state-nya berbeda-beda.

Jika backend yang dipakai adalah S3, state setiap workspace disimpan dengan prefix env:/<nama-workspace>/, misalnya env:/dev/terraform.tfstate dan env:/prod/terraform.tfstate. Praktiknya dimulai dari workspace default yang dibuat otomatis, lalu kita buat yang lain:

Membuat & berpindah workspace
terraform workspace new dev
Output workspace new
Created and switched to workspace "dev"!
 
You're now on a new, empty workspace. Workspace "dev" is the most recently
created. If you'd like to move existing resources, run "terraform workspace
select" and re-run your previous apply.
Membuat workspace staging & prod
terraform workspace new staging
terraform workspace new prod

Untuk berpindah antar workspace dan melihat status saat ini:

List, select, dan show workspace
terraform workspace list
terraform workspace select staging
terraform workspace show
Output workspace list
  default
  dev
* prod
  staging

Perhatikan tanda bintang (*) — itu menunjukkan workspace yang sedang aktif. Semua perintah plan/apply berikutnya akan bekerja terhadap state workspace aktif tersebut.

Memakai terraform.workspace di dalam Konfigurasi

Untuk membedakan nilai antar environment, Terraform menyediakan variabel bawaan terraform.workspace yang berisi nama workspace aktif. Pola paling umum adalah membuat name_prefix dan tag environment:

locals.tf
locals {
  name_prefix = "${var.project_name}-${terraform.workspace}"
 
  common_tags = {
    Environment = terraform.workspace
    Project     = var.project_name
    ManagedBy   = "terraform"
  }
}
 
module "vpc" {
  source = "./modules/vpc"
 
  name = local.name_prefix
  cidr = var.vpc_cidrs[terraform.workspace]
 
  tags = local.common_tags
}

Dengan pola ini, terraform workspace select dev lalu terraform apply akan menghasilkan VPC bernama myapp-dev, sedangkan di prod menghasilkan myapp-prod. Nilai per-environment seperti vpc_cidrs bisa disimpan dalam map yang diindeks dengan nama workspace.

Tip

terraform.workspace adalah variabel khusus yang nilainya tidak bisa dioverride dari .tfvars — ia selalu mengikuti workspace yang aktif. Gunakan ia untuk hal-hal yang memang bergantung pada nama environment (prefix nama, tag), tapi jangan menggunakannya untuk nilai-nilai yang bersifat konfigurasi murni (misal ukuran instance). Untuk itu tetap gunakan variabel biasa agar tidak ada logika tersembunyi yang bergantung pada nama workspace.

Keterbatasan Workspaces yang Sering Diremehkan

Workspaces terlihat praktis — satu kode, satu folder, beberapa state. Sayangnya, kepraktisan ini datang dengan harga yang mahal di skala enterprise:

  1. State tidak terisolasi. Semua workspace tinggal di backend yang sama (S3 bucket yang sama, DynamoDB lock yang sama). Ini berarti satu set kredensial bisa menyentuh seluruh environment.
  2. Tidak ada isolasi kredensial. Karena satu konfigurasi dan satu backend, sulit memaksa prod hanya bisa diakses oleh CI yang berhak. Siapa pun yang bisa apply di dev, secara teknis bisa workspace select prod lalu apply juga.
  3. Risiko salah switch (accidental switch). Perintah terraform apply tidak menanyakan ulang workspace mana yang sedang aktif. Konfigurasi identik untuk semua workspace membuat kesalahan tak terlihat sampai semuanya sudah terlanjur diterapkan. State lock pun hanya mengunci satu workspace — tidak mencegah dua orang mengubah dev dan prod dalam waktu bersamaan.
  4. Blast radius sama. Kesalahan kode yang membuat Terraform menghancurkan resource akan menghantam environment manapun yang sedang di-apply.
  5. Nilai terraform.workspace yang menempel di state. Jika suatu saat ingin mengganti nama workspace atau pindah strategi, moved/rename jadi menyakitkan karena prefix di resource ikut berganti.

Caution

Prinsip keselamatan utama: jika dua environment membutuhkan kredensial yang berbeda (misal akun AWS terpisah) atau proses approval yang berbeda, maka workspaces bukanlah pilihan yang tepat — karena semua environment berbagi satu sesi eksekusi. Workspaces paling cocok untuk environment ephemeral (branch preview, PR sandbox) atau tim kecil yang belum membutuhkan isolasi penuh.

Directory-Based Structure: Standar Enterprise

Pendekatan kedua sekaligus rekomendasi standar industri adalah directory-based structure: setiap environment adalah konfigurasi Terraform yang terpisah secara fisik — direktori sendiri, state backend sendiri, kredensial sendiri, dan alur eksekusi sendiri. Semua environment berbagi modul yang sama di direktori modules/, sehingga kode tetap DRY, tapi isolasinya penuh.

terraform-infra/ — struktur berbasis direktori
terraform-infra/
├── modules/
   ├── vpc/                 # Modul bersama, dipakai semua environment
   └── ec2/
├── environments/
   ├── dev/
   ├── backend.tf       # Backend S3 khusus dev
   ├── main.tf
   ├── variables.tf
   ├── locals.tf
   └── terraform.tfvars # Nilai spesifik dev
   ├── staging/
   ├── backend.tf
   ├── main.tf
   ├── variables.tf
   ├── locals.tf
   └── terraform.tfvars
   └── prod/
       ├── backend.tf
       ├── main.tf
       ├── variables.tf
       ├── locals.tf
       └── terraform.tfvars

Setiap environment punya state backend sendiri. Perhatikan key yang berbeda pada setiap file backend.tf:

environments/prod/backend.tf
terraform {
  backend "s3" {
    bucket         = "company-terraform-state"
    key            = "prod/terraform.tfstate"
    region         = "ap-southeast-1"
    encrypt        = true
    dynamodb_table = "terraform-locks"
  }
}
environments/dev/backend.tf
terraform {
  backend "s3" {
    bucket         = "company-terraform-state"
    key            = "dev/terraform.tfstate"
    region         = "ap-southeast-1"
    encrypt        = true
    dynamodb_table = "terraform-locks"
  }
}

Note

Pada contoh di atas, key sengaja berbeda (dev/ vs prod/) agar state terpisah. Namun perlu diingat: argument di dalam blok backend tidak bisa menerima variabel (var.*), jadi nilai harus ditulis langsung. Karena itulah file backend.tf dibuat per direktori environment. Pola lain yang umum adalah memisahkan bucket S3 per environment — lebih aman lagi, karena isolasi state juga ikut memisahkan akses IAM.

Nilai spesifik environment disimpan di terraform.tfvars, lalu dipetakan menjadi locals yang rapi untuk dipakai seluruh konfigurasi:

environments/dev/terraform.tfvars
environment       = "dev"
vpc_cidr          = "10.10.0.0/16"
instance_type     = "t3.micro"
enable_nat_gateway = false
environments/dev/locals.tf
locals {
  name_prefix = "${var.project_name}-${local.environment}"
 
  common_tags = {
    Environment = local.environment
    Project     = var.project_name
    ManagedBy   = "terraform"
  }
}
 
module "vpc" {
  source = "../../modules/vpc"
 
  name = local.name_prefix
  cidr = var.vpc_cidr
 
  tags = local.common_tags
}

Perhatikan source = "../../modules/vpc" — modul dirujuk dari posisi direktori environment. Konfigurasi inti (main.tf) di setiap environment menjadi hampir identik karena perbedaannya memang hanya nilai variabel.

Alur eksekusinya pun terpisah total — setiap environment dijalankan dari direktori masing-masing:

Apply terpisah per environment
cd environments/dev && terraform init && terraform apply -auto-approve
cd environments/prod && terraform init && terraform apply -auto-approve

Important

Kekuatan sebenarnya dari directory-based adalah integrasinya dengan CI/CD: di episode 13 kita akan melihat bagaimana setiap environment punya pipeline sendiri — dev bisa di-apply otomatis saat merge, sedangkan prod butuh manual approval. Kredensial per environment disuntikkan lewat OIDC dengan role AWS yang berbeda, sehingga blast radius benar-benar terkunci. Inilah alasan utama mengapa pendekatan ini menjadi standar enterprise.

Alur Kerja: Workspace vs Directory

# Satu direktori, state dibedakan via prefix env:/
terraform workspace new dev
terraform workspace select dev
terraform plan
terraform apply
 
terraform workspace select prod
terraform plan
terraform apply

Perbandingan: Workspaces vs Directory-Based

AspekWorkspacesDirectory-Based
KonsepBeberapa state dalam satu konfigurasiDirektori fisik terpisah per environment
Lokasi stateSatu backend, key env:/<workspace>/Backend (atau setidaknya key) berbeda
Isolasi stateTidak adaPenuh
Isolasi kredensial/aksesTidak ada — satu sesi eksekusiPenuh — IAM per environment/akun
Risiko salah pilih environmentTinggi (accidental switch)Rendah (kesalahan tak mungkin lewat kode)
Approval per environmentTidak mungkin dipisahMudah dipetakan ke CI/CD
Pembedaan nilaiterraform.workspace (implisit)Variabel + terraform.tfvars (eksplisit)
Cocok untukEksperimen, environment ephemeralDev/staging/prod permanen, enterprise

Rekomendasi untuk Kalian

Aturan praktis yang dipakai banyak tim:

  • Gunakan directory-based sebagai default untuk environment yang permanen dan berumur panjang (dev, staging, prod). Investasi awalnya sedikit lebih besar, tapi keuntungan isolasi state, kredensial, dan proses akan terbayar berkali-kali lipat.
  • Gunakan workspaces untuk hal yang ephemeral — misalnya preview per pull request, atau sandbox eksperimen yang dibuang setelah selesai. Workspace bagus karena murah untuk dibuat dan dihancurkan.
  • Kombinasikan keduanya — misalnya directory dev/ yang memakai workspaces untuk membedakan environment developer per orang (dev/arman, dev/siti), sementara staging/ dan prod/ tetap satu workspace default. Pola hibrid ini sangat umum dan paling fleksibel.

Apapun pilihannya, pastikan tiga hal ini selalu ada: name_prefix/tag environment yang jelas per environment, state yang bisa dilacak ke environment mana, dan proses plan yang selalu dicek sebelum apply.

Kesalahan Umum (Common Pitfalls)

1. Apply di workspace yang salah

Kebiasaan berbahaya: sibuk di dev, pindah ke task lain, lalu tanpa sadar masih di workspace prod ketika menjalankan terraform destroy. Selalu cek dengan terraform workspace show sebelum perintah destruktif, atau biasakan memakai terraform plan terlebih dahulu dan baca outputnya.

2. Menggunakan terraform.workspace untuk hal yang bukan environment

Nilai seperti ukuran instance, jumlah AZ, atau konfigurasi yang "kebetulan" berbeda antar env sebaiknya variabel biasa, bukan terraform.workspace. Menggantungkan logika pada nama workspace membuat kode sulit diuji dan menyulitkan kalau nanti pindah ke directory-based.

3. Mengabaikan isolasi kredensial

workspace select prod dengan kredensial yang sama dengan dev berarti prod bisa dihancurkan oleh siapa pun yang punya akses dev. Ini adalah alasan terkuat untuk memilih directory-based dengan akun/role terpisah.

4. backend.tf yang sama untuk semua environment

Kalau semua environment memakai key yang sama (misal terraform.tfstate), state mereka akan saling menimpa — lebih buruk dari workspace. Pastikan key (atau bucket) benar-benar unik per environment.

5. Duplikasi kode environment tanpa modul

Directory-based yang baik tetap berbagi modules/. Jika tiap environment malah punya salinan resource sendiri-sendiri (copy-paste antar folder), kalian hanya memindahkan masalah duplikasi, bukan menyelesaikannya.

6. Mencampur state workspace dengan non-workspace tanpa sadar

Saat sebuah backend beralih ke mode workspace (env:/ prefix), state lama di key lama jadi "yatim". Lakukan migrasi dengan sengaja (misal via terraform state mv ke prefix baru), jangan asal pindah backend.

Penutup

Pada episode 10 ini kita telah membandingkan dua strategi pengelolaan multi-environment secara mendalam: Terraform Workspaces — state terpisah dalam satu konfigurasi dan satu backend, praktis untuk environment ephemeral namun terbatas dalam isolasi state, kredensial, dan blast radius; serta Directory-Based Structure — setiap environment memiliki direktori, backend, dan kredensial sendiri sambil tetap berbagi modul, yang menjadi standar enterprise untuk dev, staging, dan prod yang permanen.

Poin kunci yang perlu kalian bawa pulang:

  • Isolasi yang harus dijamin: state, kredensial, blast radius, dan proses approval.
  • Workspaces berbagi satu sesi eksekusi — berisiko untuk environment permanen.
  • Directory-based memungkinkan CI/CD memisahkan alur, kredensial, dan approval per environment.
  • Gunakan name_prefix dan tag environment yang konsisten, baik lewat terraform.workspace maupun locals + terraform.tfvars.

Sekarang kalian memiliki kode yang modular dan terorganisir per environment. Namun memiliki kode "yang benar" saja tidak cukup — bagaimana memastikan kualitas dan keamanannya terjaga sebelum perubahan itu sampai ke prod? Bagaimana menangkap kesalahan sejak dini?

Di episode 11 selanjutnya kita akan membahas Formatting, Linting & Automated Testingterraform fmt dan validate, static analysis dengan tflint, security scanning dengan Checkov dan Trivy, hingga automated testing infrastruktur sungguhan menggunakan Terratest. Pastikan tetap semangat!

Belajar Terraform - Workspaces vs Directory-Based Multi-Environment | Belajar Terraform